skip to content

In Appium 3, what must a POST /session request body contain to start a session?

level: juniorimportance: must knowfreq 74%

answer

  1. one envelope, not two
  2. the W3C new-session shape
  3. alwaysMatch and firstMatch live inside
  4. desiredCapabilities is no longer accepted

basics

~10 s

Appium 3 accepts a single top-level capabilities object holding alwaysMatch and firstMatch. The older desiredCapabilities and requiredCapabilities bodies are no longer accepted, and every Appium-specific key inside carries the appium: prefix.

solid answer

~50 s

A new Appium session is one HTTP request: `POST /session`, with a JSON body whose only top-level member is `capabilities`. Inside it, `alwaysMatch` is a single object of requirements and `firstMatch` an optional array of alternatives; combining them is the W3C protocol's job. Appium 3 dropped the pre-W3C `desiredCapabilities` and `requiredCapabilities` envelopes entirely, so a client binding that still posts a flat map gets nowhere. Within the object, only W3C standard names such as `platformName` travel bare — anything Appium-specific, from `appium:automationName` to `appium:newCommandTimeout`, carries the `appium:` prefix or is nested under `appium:options`. A birdwatching sightings suite therefore sends `platformName` plus `appium:automationName` and whatever names its app and device. On success the server answers with a session id and the capabilities it actually matched, and every later command in the run is addressed under that id.

code

json · 11 lines
json
{
  "capabilities": {
    "alwaysMatch": {
      "platformName": "Android",
      "appium:automationName": "UiAutomator2",
      "appium:app": "/builds/birdwatching-sightings.apk",
      "appium:newCommandTimeout": 120
    },
    "firstMatch": [{}]
  }
}

go deeper

for a junior

Be able to write the body from memory: one capabilities object, alwaysMatch inside it, W3C names bare and Appium keys prefixed. This is asked as a screening question of anyone who has run a suite.

for a middle

Explain why the envelope changed and what happens to a client that still posts desiredCapabilities. The repair is a client upgrade, not a server setting, and you should be able to say why.

for a senior

Show that you read new-session bodies in server logs during triage, comparing the capabilities the server matched against the ones the suite believed it sent before blaming anything downstream.

for a principal

Own where capability envelopes are assembled across a suite, so one lane cannot quietly send a different session shape than another without that difference being visible in the report.

## The one request the whole run hangs on Every Appium run opens with a single HTTP request: `POST /session`, sent to the server's base path — for a server running locally that is `http://127.0.0.1:4723/session`. Nothing else can happen until it succeeds, because the response is what hands back the **session id** that every later command is addressed under. Getting the body's shape wrong is not a subtle bug: there is no session at all, and a birdwatching sightings suite dies before it has seen one screen of the app. ## The envelope Appium 3 accepts The body has exactly one top-level member, `capabilities`. Inside it sit two optional members: - **`alwaysMatch`** — one object of requirements the created session must satisfy. - **`firstMatch`** — an array of alternative objects, any one of which may satisfy the remainder. Both are W3C WebDriver negotiation inputs, and the rules for combining them belong to the protocol rather than to Appium. What belongs to Appium is what it no longer takes: **`desiredCapabilities` and `requiredCapabilities` are gone.** Appium 3 accepts `capabilities` and nothing else. A client binding old enough to post a flat `desiredCapabilities` map is not negotiating badly — it is sending a body with no member the server recognises as the request, and the repair belongs in the client library, not in a server flag that restores the old shape. ## Two vocabularies inside one object | Kind of key | How it is written | Birdwatching example | |---|---|---| | W3C standard names | bare | `platformName: "Android"` | | Everything Appium-specific | `appium:` prefixed | `appium:automationName: "UiAutomator2"` | Only the W3C standard names — `platformName`, `browserName`, `timeouts`, `webSocketUrl` and the rest of that short set — may travel unprefixed. Every vendor key carries `appium:` or is nested under `appium:options`, and that includes keys that feel like core Appium concepts rather than extensions: `appium:app`, `appium:udid`, `appium:newCommandTimeout`. ## The same envelope, two platform families The shape of the request does not change between platforms; only the values do. - **Android**: `platformName` is `Android`, and `appium:automationName` names an Android driver such as `UiAutomator2` or `Espresso`. - **Apple platforms**: `platformName` names the Apple target you mean, and `appium:automationName` is `XCUITest`. That symmetry is worth saying out loud, because it is close to the last thing about a session that is symmetric. Once the request lands, what the driver has to do on the device diverges sharply: the Android drivers push a helper server onto the device, while the XCUITest driver has to have WebDriverAgent built, installed and running before it will answer a command. The request looks the same on both; the seconds it takes do not. ## What comes back A successful `POST /session` answers with the session id and the set of capabilities the server actually matched. Log the matched set. It is what the driver ran with, and it is not guaranteed to be key-for-key what you sent, because which keys mean anything depends on which driver answered — `appium:deviceName`, for instance, is declared by the Android drivers and by the XCUITest driver rather than by Appium's core. The session id itself is minted for this session and is meaningless afterwards: it is not a device identifier, not a run identifier, and not stable between runs. ## Where a birdwatching suite gets this wrong 1. **Sending `desiredCapabilities`.** Almost always an unupgraded client binding rather than hand-written JSON, and the symptom is total: no session is created, on any device. 2. **Hoisting `alwaysMatch` or `firstMatch` to the top level.** They live inside `capabilities`, not beside it. 3. **Dropping the `appium:` prefix on a vendor key.** The server does not quietly accept an unprefixed vendor name and carry on regardless. 4. **Assuming the response echoes the request.** It reports what was matched, which is the more useful of the two things to read. 5. **Hand-rolling the request when a client binding exists.** The bindings build this envelope for you; the value in knowing its shape is that you can read a rejected new-session request in a server log and see immediately which half is wrong. ## Why the shape matters beyond the first request The new-session body is the only place a run gets to say what it wants. There is no later negotiation and no second chance to add a key: everything the session does afterwards — which driver answers, which device it drives, how long it may sit idle before the server ends it — was fixed by this one object. So triage of a strange run starts here rather than at the failing command. If the capabilities the server logged are not the capabilities you believed the suite sent, nothing downstream will make sense, and the fastest way to find that out is to compare the two before reading another line of the log.

  • A client still posts desiredCapabilities to an Appium 3 server. What do you change?
    The client. Appium 3 accepts only a `capabilities` object, so a binding that sends the older flat map has no path to a session at all. Upgrade the client library rather than hunting for a server flag that restores the old envelope — there is not one.
  • Does the new-session body look different for an Android session and an Apple-platform one?
    No. The envelope is identical: one `capabilities` object with `alwaysMatch` inside it. Only the values change — `platformName`, and the driver named by `appium:automationName`. What differs between the two platform families is what the driver does on the device after the request lands, not the request itself.

saying these in an interview costs you the question

  • Says Appium still accepts desiredCapabilities alongside capabilities
  • Puts alwaysMatch and firstMatch at the top level of the body
  • Thinks every capability may be sent without the appium: prefix
  • Believes the response simply echoes the capabilities that were sent
  • Treats the session id as a stable device or run identifier