Driftstack DRIFTSTACK docs
Docs

Quickstart

This guide takes you from a fresh signup to your first iPhone Safari session from code. Allow about five minutes. A session is a phone browser running in Driftstack’s cloud — your code tells it where to go and what to do, and it reports back what it sees.

This code quickstart requires a paid tier with API access. Every paid Driftstack tier, including the Manual tiers, can create a ds_live_… customer API key. On Free, start in the desktop app instead: browser sign-in automatically stores a restricted ds_test_… device credential, so there is no customer API key to create or paste. That device credential is for the supported desktop surface; it is not a general sandbox or SDK key.

You will need:

  • A Driftstack account (sign up or sign in)
  • Any paid Driftstack tier (Manual, API, or Enterprise)
  • A ds_live_… customer API key (created in the dashboard under API keys)
  • Node.js 18+, Python 3.10+, or Go 1.22+

1. Get an API key

After signing up and verifying your email:

  1. Open app.driftstack.dev/api-keys.
  2. Click Create key, give it a name (e.g. quickstart), and copy the value. The key is shown once.
  3. Export it in your shell:
export DRIFTSTACK_API_KEY="ds_live_…"

Customer API keys are scoped to the account that created them and carry the ds_live_ prefix on every paid tier, including Manual. Free does not mint customer API keys: its ds_test_… value is the restricted device credential the desktop app obtains and stores automatically after browser authorization.

If an account is downgraded to Free, existing ordinary API keys and OAuth access tokens receive 403 Forbidden. They become usable again after an upgrade unless they were revoked or expired. A denied response uses the normal RFC 9457 Forbidden problem and an actionable detail such as The "apiAccess" feature is not available on the "free" tier. Upgrade to a tier that includes this feature.

2. Install the SDK

Pick the language you want to use. See SDK installation for full details.

TypeScript / Node.js:

npm install @driftstack/sdk

Python:

pip install driftstack-sdk

Go:

go get github.com/driftstackdev/driftstack-api/packages/sdk-go

All three SDKs are published pre-1.0: TypeScript on npm, Python on PyPI, and Go as a tagged module. Keep your package-manager lockfile, Python constraints, or go.sum under version control for reproducible installs.

3. Run your first session

This snippet creates a session, navigates to a URL, captures a screenshot, and tears the session down.

TypeScript:

import { Driftstack } from '@driftstack/sdk';

const client = new Driftstack({ apiKey: process.env.DRIFTSTACK_API_KEY! });

const session = await client.sessions.create({ label: 'quickstart' });
await client.sessions.navigate(session.id, { url: 'https://example.com' });
const shot = await client.sessions.capture(session.id, { kind: 'screenshot' });
console.log('captured:', shot);
await client.sessions.destroy(session.id);

Python (sync):

import os
from driftstack import Driftstack

with Driftstack(api_key=os.environ["DRIFTSTACK_API_KEY"]) as client:
    session = client.sessions.create({"label": "quickstart"})
    client.sessions.navigate(str(session.id), {"url": "https://example.com"})
    shot = client.sessions.capture(str(session.id), {"kind": "screenshot"})
    print("captured:", shot)
    client.sessions.destroy(str(session.id))

Go:

package main

import (
    "context"
    "log"
    "os"

    driftstack "github.com/driftstackdev/driftstack-api/packages/sdk-go"
)

func main() {
    client := driftstack.New(os.Getenv("DRIFTSTACK_API_KEY"))
    defer client.Close()

    ctx := context.Background()
    session, err := client.Sessions.Create(ctx, &driftstack.CreateSessionRequest{Label: "quickstart"})
    if err != nil { log.Fatal(err) }

    if _, err := client.Sessions.Navigate(ctx, session.ID, &driftstack.NavigateRequest{URL: "https://example.com"}); err != nil {
        log.Fatal(err)
    }
    if _, err := client.Sessions.Capture(ctx, session.ID, &driftstack.CaptureRequest{Kind: "screenshot"}); err != nil {
        log.Fatal(err)
    }
    if err := client.Sessions.Destroy(ctx, session.ID); err != nil {
        log.Fatal(err)
    }
}

4. What happened

  • client.sessions.create() reserved one of your account’s concurrent session slots. Each tier has a concurrent cap (Free: 1, API Starter: 2, API Builder: 8, API Scale: 24 — see pricing). Exceeding the cap returns 429.
  • client.sessions.navigate() drove the iPhone Safari runtime to the URL on Driftstack’s WebKit build. The runtime is built from Apple’s WebKit source directly — not a Chromium-stealth shim pretending to be Safari.
  • client.sessions.capture() returned a { kind, data, encoding, byte_size, duration_ms } object. For a screenshot, data is the PNG base64-encoded (encoding: "base64"), so decode it to bytes before saving — e.g. fs.writeFileSync('shot.png', Buffer.from(shot.data, 'base64')). A dom_snapshot capture instead returns the raw HTML as UTF-8 text (encoding: "utf8").
  • client.sessions.destroy() released the concurrent slot. Only free-tier sessions stop on their own (at the 20-minute cap) — on paid tiers a forgotten session holds its slot until you destroy it.

5. Next steps

  • Profile management — persistent profiles let a session resume cookies, storage, and trust signals across runs.
  • Session lifecycle — full lifecycle reference (states, the free-tier 20-minute duration cap, recovery on reconnect).
  • Agent sessions — natural-language decompose-and-execute on top of any driver session. Three operational modes: AI (default), manual (pass-through), pair (interactive takeover state machine). Live transcript stream via Server-Sent Events.
  • Bundled LLM and BYOK Anthropic — the two LLM rails agent sessions can use. BYOK encrypts your Anthropic key at rest + decrypts in-memory only at execution; the bundled rail uses a deployment-managed budget for accounts that don’t want to manage their own key.
  • Idempotency keysIdempotency-Key is honoured on four endpoints: agent-session creation, agent-session messages, and the two billing checkouts. It is not honoured on POST /v1/sessions — the sessions.create() call above. Retrying that after a timeout mints a second session and takes another concurrent slot, so guard it yourself (reuse the session id you already got back, or check client.sessions.list() before retrying).
  • Webhook event catalog — push notifications when sessions transition state, billing events fire, etc.
  • API versioning policy — what changes are additive, what triggers /v2/*, deprecation cycles.

Stuck? Email support@driftstack.dev. Include your account ID (acc_…) + the request ID from any error response (returned in the x-request-id header) so we can trace it.