> ## Documentation Index
> Fetch the complete documentation index at: https://docs.uplink.build/llms.txt
> Use this file to discover all available pages before exploring further.

# Your First Session

> What to say to your AI client to pair a device and start driving it

A session has to exist and have a device on it before anything can drive a page, so the order below matters.

## Pair a device

Ask for a session:

> Start an Uplink session

You get back a link to a pairing page. Open it, then pair from there:

<Steps>
  <Step title="Open the pairing page">
    Your client hands you a link to Uplink Console. Open it on your desktop — it shows a QR code, a pairing code, and live connection status.
  </Step>

  <Step title="Point your phone at it">
    **iPhone** — scan the QR with the Camera app. It launches the Connect **App Clip**; nothing to install.

    **Android** — install [Connect](https://play.google.com/store/apps/details?id=build.uplink.connect) first, then scan from inside the app.

    **Connect already open?** Type the 6-digit code instead.
  </Step>

  <Step title="Wait for it to catch">
    The page flips to connected, and your client notices on its own. You don't need to tell it you're done.
  </Step>
</Steps>

<Tip>
  Pairing codes last 30 seconds. If yours expires, say *"get me a fresh pairing code"* — no need to start over.
</Tip>

## Drive the page

Now talk to the site through the phone:

> Go to news.ycombinator.com and tell me what the top story is

> Log into my account — I'll type the password on my phone

> Click through to the account page and show me the DOM

You are driving a real browser on a real device, so anything you'd do by hand works.

## A worked example

Say you want to analyze your own auto insurance coverage — pull the limits, deductibles, and vehicles off your policy so you can check for gaps, and then keep pulling it as it changes.

Pair a device, then:

> Go to my insurer's site and stop at the login page

Log in on the phone yourself, including whatever 2FA it asks for — credentials are typed on the device and never reach your AI client.

> I'm in. Navigate to my policy details

> What network requests fired loading that page? I'm looking for whichever one returns the coverage data

Your client comes back with the requests the site actually made — not the rendered page, the JSON behind it. Usually one of them is obvious:

```
GET https://api.myinsurer.com/v2/policies/POL-4417/declarations
  200 · application/json · 14.2 KB
```

> Show me the full response body for that one

Now you have the real shape: `coverages[]` with `type`, `limitPerPerson`, `limitPerOccurrence`, `deductible`, and a `vehicles[]` alongside it. Ask for the analysis:

> Compare my liability limits against my state's minimums and flag anything underinsured

And then make it repeatable:

> Write me an SDK script that logs in, calls that declarations endpoint, and prints the coverage table

You get a standalone script — it runs on its own against the [JavaScript SDK](/api-reference/overview), with no dependency on the MCP server or on your AI client:

```typescript theme={null}
import uplink from '@uplink-code/uplink'

const session = await uplink.session(
  {
    clientId: process.env.UPLINK_CLIENT_ID,
    clientSecret: process.env.UPLINK_CLIENT_SECRET,
  },
  { include: { ecdsa: true, ecdh: true } },
)

// Present session.qrUrl to the policyholder so they can pair and sign in.
const client = await uplink.client.fromSession(session)
const browser = await client.launch()
const page = await browser.newPage()

await page.goto('https://www.myinsurer.com/login')
// ...the user authenticates on their device...

// Called from the device, so it carries the session the user just established.
const result = await page.request(
  'https://api.myinsurer.com/v2/policies/POL-4417/declarations',
)
const { coverages, vehicles } = await result.json()

for (const c of coverages) {
  console.log(`${c.type}: ${c.limitPerPerson}/${c.limitPerOccurrence}, $${c.deductible} deductible`)
}

await client.close()
```

<Note>
  The MCP server is where you *discover* how a site works, interactively and once. The SDK is where you run it — on a schedule, for many users, without an AI in the loop.
</Note>

## Prompts that work well

<AccordionGroup>
  <Accordion title="Finding an undocumented API">
    > Drive to the page that shows my order history, then show me every XHR the page made and which one has the orders in it
  </Accordion>

  <Accordion title="Understanding an auth flow">
    > I'm going to log in on my phone. Capture every request during login and tell me how the session token gets set
  </Accordion>

  <Accordion title="Debugging a broken flow">
    > Walk through checkout and stop when something fails. Show me the console errors and the last request before it broke
  </Accordion>

  <Accordion title="Checking a page renders">
    > Go to this URL and give me the DOM snapshot — I want to know if the price is server-rendered or filled in by JS
  </Accordion>
</AccordionGroup>

## When something goes wrong

| What you see                          | What to say                                                              |
| ------------------------------------- | ------------------------------------------------------------------------ |
| Pairing code expired                  | *"Get a fresh pairing code"*                                             |
| Phone never connected                 | *"Is my device still paired?"*                                           |
| Client seems to have lost the session | *"Start a new Uplink session"* — sessions don't survive a client restart |
| A call hangs                          | Re-pair. A device that dropped off leaves the page it was driving behind |

For what the model is actually calling underneath, see the [tool reference](/mcp/tools).
