Llim.run

Instance spec and status

Every create call takes metadata and spec, and every instance reports its URLs and state in status. The spec tables cover iOS simulators and Android emulators; the lifecycle, status, timeout, and placement rules apply to Xcode and Gradle sandboxes too. Build-specific settings for sandboxes live in Build with Xcode and Build with Gradle. For what the fields mean in practice, start with Concepts; for the calls themselves, see SDKs and REST API.

Lifecycle states

Every iOS, Android, Xcode, and Gradle instance moves through the same lifecycle: creating while hardware is provisioned, assigned while it boots, ready when the URLs in status are usable, and finally terminated.

   creating ──┬──► assigned ──► ready ──► terminated
              │
              └──► (error) ──► terminated  (status.errorMessage set)
StateMeaning
unknownDefault placeholder; not returned for live instances.
creatingProvisioning. URLs in status are not populated yet.
assignedHardware is assigned and the instance is booting.
readyFully booted. All URLs are populated, and a control client can connect.
terminatedStopped by an explicit delete, the inactivity timeout, the hard timeout, or an error.

status.errorMessage is set when the instance terminated because of an error. A create call with wait: true returns once the instance is ready.

Status fields

A ready instance carries the URLs its data plane needs in status. Every URL authenticates with the instance token, never the API key.

FieldiOSAndroidXcode and GradleUse
state✓✓✓The lifecycle state.
token✓✓✓Instance token for apiUrl, endpointWebSocketUrl, adbWebSocketUrl, and mcpUrl. Embedded in signedStreamUrl. Returned only to a credential that can control the instance; a read-only API key or a viewer seat gets no token.
streamToken✓✓Streaming-only token: opens endpointWebSocketUrl and nothing else, so a browser can hold it while status.token stays on your backend. Returned with token; get and list return it only while the instance runs.
apiUrl✓✓✓HTTP base for the instance's daemon; pass it to the SDK and CLI control clients. On Android, the control WebSocket derives from it as apiUrl + /ws, and recording downloads use the same base.
signedStreamUrl✓✓Console-hosted watch URL with the token in the URL fragment, so the token never reaches a server. Opens in a browser without an API key or sign-in.
endpointWebSocketUrl✓✓WebSocket for the <RemoteControl /> component; pass ?token=<status.token>.
mcpUrl✓✓The instance's MCP HTTP endpoint. Authenticate with status.token as Authorization: Bearer. See Per-instance MCP server; for one endpoint that also creates instances, see the remote MCP server.
adbWebSocketUrl✓ADB tunnel endpoint. Pass it as adbUrl to createInstanceClient.
targetHttpPortUrlPrefix✓✓Prefix for reaching HTTP services that run on the device. Append the target port, with no slash, to forward traffic; Appium uses it to reach WebDriverAgent.
sandbox.playwrightAndroid.url✓ (when enabled)Chrome DevTools Protocol URL when spec.sandbox.playwrightAndroid.enabled is true. See Playwright.
sandbox.xcode.url✓ (legacy)Embedded Xcode sandbox URL on instances that old clients created with spec.sandbox.xcode.enabled. The TypeScript SDK and CLI no longer offer it; create the Xcode sandbox separately and attach the simulator. See Move off the embedded Xcode sandbox.
errorMessage✓✓✓Set when the instance terminated because of an error.
terminationReason✓✓✓Present once state is terminated, never before. Known values: UserRequested (a delete request), InactivityTimeout, HardTimeout, and Unknown (a cause the platform did not attribute, including instances that failed to become ready; see errorMessage). New values may be added, so treat unrecognized ones as Unknown.

The iOS and Android status blocks otherwise have the same shape. Reaching a server that runs inside the simulator (through targetHttpPortUrlPrefix) is the opposite direction from letting the device reach your machine; for that, see Connect to local services for iOS or Android.

Example create response

A successful Android create with wait: true returns the full instance resource. An iOS response has the same shape without adbWebSocketUrl:

{
  "metadata": {
    "id": "android_usw1_01krxvphn8e3rbeq0zewgw209a",
    "createdAt": "2026-05-18T19:52:42Z",
    "organizationId": "org_01kr52j...",
    "displayName": "android_usw1_01krxvphn8e3rbeq0zewgw209a",
    "labels": { "app": "demo", "session": "docs" }
  },
  "spec": {
    "inactivityTimeout": "10m0s",
    "region": "us-west2"
  },
  "status": {
    "state": "ready",
    "apiUrl":               "https://us-west2-1234567.limrun.net/v1/android_usw1_01krxv.../api",
    "adbWebSocketUrl":      "wss://us-west2-1234567.limrun.net/v1/organizations/org_01kr52j.../android.limrun.com/v1/instances/android_usw1_01krxv.../adbWebSocket",
    "endpointWebSocketUrl": "wss://us-west2-1234567.limrun.net/v1/organizations/org_01kr52j.../android.limrun.com/v1/instances/android_usw1_01krxv.../endpointWebSocket",
    "signedStreamUrl":      "https://console.limrun.com/signedStream?url=wss%3A%2F%2Fus-west2-1234567.limrun.net%2F...%2FendpointWebSocket#token=lim_...",
    "mcpUrl":               "https://us-west2-1234567.limrun.net/v1/android_usw1_01krxv.../mcp",
    "targetHttpPortUrlPrefix": "wss://us-west2-1234567.limrun.net/v1/organizations/org_01kr52j.../android.limrun.com/v1/instances/android_usw1_01krxv.../targetHttpPort",
    "token": "lim_...",
    "streamToken": "lim_..."
  }
}

The metadata and spec fields in the response:

FieldUse
metadata.idStable instance identifier. Pass it to get, delete, and connect.
metadata.labelsEchoed back. Drives reuseIfExists matching and label-selector listing.
metadata.displayNameHuman-readable name shown in the console.
spec.regionThe region the scheduler placed the instance in.
spec.inactivityTimeoutReturned as a Go duration string ("10m0s"), not the "10m" you passed.

Create parameters

Every create call, for any instance type, accepts these parameters next to spec:

FieldTypeMeaning
waitbooleanWhen true, the call returns only after status.state === 'ready'; without it, poll. Default false.
reuseIfExistsbooleanWhen true, return the existing instance whose metadata.labels match exactly instead of creating one. The lookup runs in the region that handles the create, so a placement change can miss. Default false.
metadata.labelsRecord<string, string>Free-form key=value map. Powers reuseIfExists, labelSelector listing, and bulk cleanup. See Labels.
metadata.displayNamestringHuman-readable name shown in the console next to metadata.id.

Timeouts

Two timeouts end an instance without a delete call. Both take a duration string such as 1m, 10m, or 3h.

A terminated instance reports which one fired in status.terminationReason.

iOS spec

The spec fields accepted by iosInstances.create (TypeScript names; Python uses snake_case). The CLI flags for the same fields are in Run a simulator.

FieldTypeMeaning
spec.model'iphone' | 'iphone-duo' | 'ipad' | 'watch'Apple Simulator model. Default iphone. iphone-duo must be available to your organization. The Go SDK does not expose this field.
spec.jurisdiction'us' | 'eu' | 'as'Hard constraint: schedule only inside this jurisdiction; creation fails when no region there has capacity. TypeScript SDK, CLI, and REST only. See Placement.
spec.regionstringDeprecated. A region preference such as us-east1, not a hard pin. See Placement.
spec.inactivityTimeoutduration stringSee Timeouts.
spec.hardTimeoutduration stringSee Timeouts.
spec.forceBundleIdstringAfter this app first enters the foreground, Limrun brings it back whenever it is closed or backgrounded. It does not launch the app at startup.
spec.clues[]arrayPlacement hints: ClientIP with the end user's IP, or ClientLocation with coordinates (TypeScript SDK and REST only). See Client location clues.
spec.initialAssets[]arrayApps or keychain state to apply at boot. App entries use kind: 'App' with source URL, AssetName, or AssetID, plus an optional launchMode of ForegroundIfRunning or RelaunchIfRunning; omit launchMode to install without launching. Keychain entries use kind: 'Keychain' and require encryptionKey. See Pre-install at boot and Save and restore the keychain.
spec.sandbox.xcode.enabledbooleanLegacy: create an embedded Xcode sandbox with the simulator. The API still accepts it for old clients, but the TypeScript SDK (from 0.54.0) and CLI (from 0.35.0) no longer offer it. Create the sandbox separately and attach instead; see Move off the embedded Xcode sandbox.
Console Playground iOS model picker showing iPhone, iPad, and Apple Watch options

Android spec

The spec fields accepted by androidInstances.create. The CLI flags for the same fields are in Run an emulator.

FieldTypeMeaning
spec.model'phone' | 'tablet'Android device model. Default phone. TypeScript SDK, CLI, and REST only; the Python and Go SDKs do not expose it.
spec.jurisdiction'us' | 'eu' | 'as'Hard constraint: schedule only inside this jurisdiction; creation fails when no region there has capacity. TypeScript SDK, CLI, and REST only. See Placement.
spec.regionstringDeprecated. A region preference such as us-east1, not a hard pin. See Placement.
spec.inactivityTimeoutduration stringSee Timeouts.
spec.hardTimeoutduration stringSee Timeouts.
spec.clues[].kind'ClientIP' | 'ClientLocation' | 'OSVersion'Placement hint: bias by Android version or by the end user's location.
spec.clues[].clientIpstringRequired when kind: 'ClientIP'. The IP of the end user whose browser streams the emulator; the scheduler geolocates it and provisions in the nearest region. spec.region overrides this clue.
spec.clues[].clientLocationobject{ latitude, longitude } in decimal degrees when kind: 'ClientLocation'. Both coordinates are required. Takes precedence over ClientIP. TypeScript SDK and REST only.
spec.clues[].osVersionstringRequired when kind: 'OSVersion'. The Android major version, '14' or '15'.
spec.initialAssets[]arrayAPKs to install while provisioning, plus Configuration entries such as Chrome flags. Plural sources install split APKs as one group. See Pre-install APKs.
spec.sandbox.playwrightAndroid.enabledbooleanProvision a Playwright sub-sandbox next to the emulator and report its CDP URL in status.sandbox.playwrightAndroid.url. Default false. See Playwright.
spec.sandbox.playwrightAndroid.version'1.56.1-lim.1' | '1.60.0-lim.1'Playwright server version for the sub-sandbox. Omit it for 1.56.1-lim.1. Your Playwright client version must match.

The CLI's --os-version and --model flags set the OS version and model. It has no flags for the ClientIP and ClientLocation clues or for spec.sandbox.playwrightAndroid; set those from an SDK or REST.

Labels

metadata.labels is a free-form { [key: string]: string } map used for reuse, listing, and cleanup; Labels and reuse explains how. Avoid keys that could collide with metadata Limrun adds itself, such as the created-by: mcp label on instances the remote MCP server creates.

Placement

spec.jurisdiction (us, eu, or as) keeps an instance inside one jurisdiction. It is a hard constraint: creation fails when no region there has capacity.

spec.region is deprecated. It is a preference, such as eu-north1 or us-east1, that is tried first and overflows to other regions by proximity when the preferred ones are full. When both are omitted, Limrun places the instance by spec.clues and current availability.

jurisdiction is available in the TypeScript SDK and the CLI today; the Python and Go SDKs expose only region. The console's Analytics tab breaks down runtime minutes per platform and per region, which shows which regions your organization has used:

Console Analytics tab showing daily runtime minutes for Android, iOS, and XCode, broken down by eu-north1 and us-east1 regions

Client location clues

When you create an Android, iOS, Xcode, or Gradle instance through the REST API, supply the end user's coordinates as a ClientLocation clue to prefer a nearby region:

{
  "spec": {
    "clues": [
      {
        "kind": "ClientLocation",
        "clientLocation": {
          "latitude": 37.7749,
          "longitude": -122.4194
        }
      }
    ]
  }
}

Both coordinates are required and use decimal degrees. Latitude must be between -90 and 90, and longitude between -180 and 180, inclusive. Zero is valid. Missing or invalid coordinates return HTTP 400.

ClientLocation takes precedence over ClientIP regardless of their order in spec.clues. Without coordinates, pass { "kind": "ClientIP", "clientIp": "203.0.113.42" } to locate the end user by IP. For requests without either clue, Limrun uses available visitor coordinates first, then the connecting IP.

Location clues express a preference. spec.jurisdiction still constrains placement, and a full region can lead to creation in another eligible region. A specific spec.region overrides location clues. Use the REST payload above if your installed SDK does not expose ClientLocation yet.

For embedded devices, always pass the end user's location or IP. It places the instance near the person streaming it, which is the difference between a responsive device and one that lags across continents.

Next steps

book-open

Concepts

Instances, credentials, labels, and placement explained.

book-open

SDKs and REST API

The create, list, get, and delete calls in every language.