For AI agents and LLMs: a machine-readable index is available at llms.txt. A plain-Markdown version of any documentation page is available by appending .md to its URL.
Skip to main content

Getting Started with TestMu AI's SmartUI Figma-App CLI


SmartUI Figma-App CLI lets you compare mobile app screenshots captured on real devices with your Figma design frames to detect visual mismatches and ensure accurate implementation of mobile UI.

The workflow has two halves. First you upload your Figma frames to SmartUI as the baseline using the CLI. Then you run your Appium test suite on the real device cloud so your app screenshots land in the same project and get compared against those frames. This guide covers both halves end to end.


Prerequisites

  • Node.js and npm installed
  • TestMu AI SmartUI account with App Automation plan
  • Your TestMu AI Username and Access Key from the Account Settings page
  • Figma Personal Access Token (how to get one)
  • An Appium test suite for your app
  • Your app uploaded to the real device cloud so you have an app_url. See Upload your app

Understanding the Tokens and Credentials

The Figma-App workflow needs four values across its two halves. Two are used by the CLI upload, two by the Appium run.

TokenWhere It Is UsedDescription
PROJECT_TOKENEnv VariableYour SmartUI project token. Authenticates the CLI upload
FIGMA_TOKENEnv VariableYour Figma Personal Access Token to authenticate with the Figma API
LT_USERNAMEEnv VariableYour TestMu AI username. Used in the Appium grid URL
LT_ACCESS_KEYEnv VariableYour TestMu AI access key. Used in the Appium grid URL
figma_file_tokendesigns.jsonFigma file ID, extracted from the Figma file URL
figma_idsdesigns.jsonList of frame or node IDs you want to compare visually
warning

Do not set any of these to an empty string. The CLI treats an empty value as an error and exits with Missing FIGMA_TOKEN in Environment Variables (or the matching LT_USERNAME / LT_ACCESS_KEY message), while leaving the same variable unset is accepted. If you hit that message, check for a stray export FIGMA_TOKEN= in your shell.

Example Figma URL: https://www.figma.com/design/abc12345/file-name?node-id=2417-58969

  • figma_file_token: abc12345
  • figma_ids: 2417-58969

Older Figma links use /file/ instead of /design/. Both forms carry the file ID in the same position.


Step-by-Step Guide

1. Create a SmartUI Project

  1. Visit smartui.lambdatest.com
  2. Click New Project
  3. Select Real Devices as the platform
  4. Enter:
    • Project Name (required)
    • Approver(s) (required, pre-filled with your own user)
    • Tags (optional)
  5. Click Continue

Note down both the project name and the project token. You need the token for the CLI upload and the name for your Appium capabilities.


2. Install SmartUI CLI

npm install -g @lambdatest/smartui-cli

3. Generate and Edit Configuration

Run the following to create your initial design file:

npx smartui config:create-figma-app designs.json

The file must have a .json extension, and the command refuses to overwrite a file that already exists.

Sample designs.json

designs.json
{
"mobile": [
{
"name": "Pixel 8",
"platform": ["android 14"],
"orientation": "portrait"
}
],
"figma": {
"depth": 1,
"configs": [
{
"figma_file_token": "abc12345",
"figma_ids": ["2417-58969"],
"screenshot_names": ["homepage"]
}
]
}
}

Configuration Options

Config KeyDescriptionUsage
mobile[].nameDevice name. This must be an exact match for a supported device, and the same device you run your Appium test on. An unsupported value fails validation with unsupported mobile device name. The generated config seeds valid examples you can start from.Mandatory
mobile[].platformOperating system and version for the device, for example ["android 14"] or ["ios 17"].Optional
mobile[].orientationEither portrait or landscape. No other value is accepted.Optional
figma.depthPositive integer controlling how deep into the Figma document tree the fetch traverses. The generated config uses 1.Optional
figma.configs[].figma_file_tokenFile token for your Figma file. You can list multiple files in the same configuration.Mandatory
figma.configs[].figma_idsList of node or frame IDs you want to compare. Values must be unique.Mandatory
figma.configs[].screenshot_namesNames given to the uploaded frames. If you supply this array it must have exactly the same number of entries as figma_ids, in the same order. Names must be unique across the whole file.Optional
smartIgnoreTop level boolean accepted by the config schema and forwarded with the upload.Optional
note

If you add a property that is not listed above, the CLI logs Additional property "<name>" is not allowed as a warning and then continues with the upload. The extra key is ignored rather than applied, so check for this warning if a setting you added appears to have no effect.


4. Set Environment Variables

Set all four values before running the upload.

export PROJECT_TOKEN="123456#1234abcd-****-****-****-************"
export FIGMA_TOKEN="figd_****************************************"
export LT_USERNAME="YOUR_USERNAME"
export LT_ACCESS_KEY="YOUR_ACCESS_KEY"

5. Upload your Figma designs as the baseline

npx smartui upload-figma-app designs.json --buildName "figma-baseline" --markBaseline

Uploaded frames are stored with a .png suffix. A frame named homepage in screenshot_names becomes homepage.png in the build. Remember this, because your app screenshot names have to match it in Step 8.

Optional Flags

FlagDescription
--markBaselineMark this build as a new baseline for future runs
--buildNameAssign a custom name to this comparison build
--fetch-results [filename]Poll for build results after the upload. Accepts an optional output file name, for example results.json

Example

npx smartui upload-figma-app designs.json --buildName "v1.0.0" --markBaseline --fetch-results results.json

6. Upload your app

Your Appium test needs an app that lives on the real device cloud. Upload your .apk or .ipa and note the app_url that is returned.

curl -u "$LT_USERNAME:$LT_ACCESS_KEY" \
-X POST "https://manual-api.lambdatest.com/app/upload/realDevice" \
-F "appFile=@/path/to/your/app.apk" \
-F "name=YourAppName"

The response contains an app_url field, already in lt://APP... form, which is the value you pass as the app capability in the next step. For other upload options see Upload your app.


7. Configure your Appium capabilities

This is the half that produces the app screenshots. Use the same device here as in designs.json so both sides are captured at the same viewport.

NodeJS example
let capabilities = {
deviceName: "Pixel 8", // must match mobile[].name in designs.json
platformName: "android",
platformVersion: "14", // must match mobile[].platform
isRealMobile: true, // Mandatory
app: "lt://APP_ID", // Mandatory
visual: true, // Mandatory
name: "Figma app comparison",
build: "Real Device App Build",
"smartUI.project": "<Your Project Name>", // Mandatory, the project NAME not the project token
"smartUI.build": "<Your Build Name>", // Optional
"smartUI.baseline": false, // Leave false, your Figma build is the baseline
};

let gridUrl =
"https://" +
"<Your Username>" +
":" +
"<Your Access Key>" +
`@mobile-hub.lambdatest.com/wd/hub`;

let driver = await new webdriver.Builder()
.usingServer(gridUrl)
.withCapabilities(capabilities)
.build();
warning

The app side is identified by smartUI.project, which takes the project name. The PROJECT_TOKEN you exported in Step 4 authenticates the CLI upload only. It is not used by the Appium capabilities.

warning

visual: true is mandatory. Without it no screenshots are sent to SmartUI and the build is reported with an Error status.


8. Capture screenshots with matching names

Add the screenshot hook after the point in your script where the screen you care about is rendered.

Critical: Figma frames are stored with .png appended, so your app screenshot names must include the extension to line up with them.

// ❌ Wrong, will not match the Figma frame
await driver.execute("smartui.takeScreenshot=homepage");

// ✅ Correct, matches the Figma frame homepage.png
await driver.execute("smartui.takeScreenshot=homepage.png");
warning

When you pass a config object, the screenshot name key is screenshotName. Passing name throws Error response status: 1 and the test fails.

// ❌ Wrong, throws
await driver.execute("smartui.takeScreenshot", {name: "homepage.png"});

// ✅ Correct
await driver.execute("smartui.takeScreenshot", {screenshotName: "homepage.png"});
// simple form
await driver.execute("smartui.takeScreenshot=homepage.png");

// config form
await driver.execute("smartui.takeScreenshot", {screenshotName: "homepage.png"});

Run your test suite as you normally would.

npm i && node your_test_script.js

9. View SmartUI Results

You can see the SmartUI dashboard to view the results. This will help you identify the Mismatches from the existing Baseline build and do the required visual testing.

cmd

How the comparison is paired

Three things have to line up for a Figma frame and an app screenshot to be compared:

  1. Same project. The CLI upload targets it by PROJECT_TOKEN and the Appium run targets it by smartUI.project. Both must resolve to the same Real Devices project.
  2. Figma build is the baseline. Upload the Figma designs with --markBaseline, or approve that build on the dashboard. Your app run then becomes the comparison build.
  3. Screenshot names match exactly. A frame stored as homepage.png is only compared against an app screenshot named homepage.png.

The device in designs.json and the device in your capabilities should also match, so both sides are captured at the same viewport.


Best Practices

Build Names

Give each run a build name you can trace back to a release or a commit.

npx smartui upload-figma-app designs.json --buildName "v1.0.0"

Troubleshooting

Uploads fail with an authentication error

Check that all four values are set in the shell you are running from.

echo $PROJECT_TOKEN
echo $FIGMA_TOKEN
echo $LT_USERNAME
echo $LT_ACCESS_KEY

A missing LT_USERNAME or LT_ACCESS_KEY is the most common cause. The CLI reports the missing variable by name.

The config file is rejected

  • Verify the figma_file_token in your designs.json matches the file ID from the Figma URL
  • Ensure the account behind your Figma token has access to that file

The upload fails while fetching from Figma

The upload authenticates and then fails during Processing App Figma with a message like:

Failed to retrieve figma files, Figma API rate limit reached for your token.
Your file is on the 'starter' plan tier, and your token's rate-limit bucket is 'low'.

Figma applies the lowest rate-limit bucket to tokens that act as a Viewer or Collab seat on a file, which includes free Starter workspaces. A handful of uploads in quick succession is enough to exhaust it.

What helps:

  • Wait before retrying. Short backoff often is not enough, so leave a longer gap between attempts
  • Reduce how many figma_ids you fetch per run, and avoid re-running the upload while iterating on unrelated config
  • Use a token belonging to an Editor seat on a paid Figma tier, which is placed in a higher bucket

A direct call to the Figma REST API can still succeed while the upload fails, because the upload makes several calls per run.

Figma frames and app screenshots are not being compared

  • Ensure app screenshots include the .png extension, for example homepage.png
  • Verify names match exactly between the Figma config and your Appium code, including case
  • Ensure screenshot_names matches the order of figma_ids

If you encounter issues not covered here:

Additional Resources


Run seamless visual comparisons between real device screenshots and Figma designs with SmartUI CLI. Start validating your mobile UI today!

Test across 3000+ combinations of browsers, real devices & OS.

×
Schedule Your Personal Demo
Book Demo

Help and Support

Related Articles