Skip to main content

Test on the real engine.

Your users are on iPhones. Your test grid probably isn't. Driftstack gives your tests an iPhone Safari browser in the cloud, started with one API call. It runs a build of Apple's own WebKit, the engine family behind iPhone Safari, on Macs.

The bug you can't reproduce is on a phone.

Mobile Safari is its own world: its own rendering, its own JavaScript timing, its own quirks. A desktop browser shrunk to 390 pixels wide does not reproduce it. The layout break your iPhone users hit simply isn't there. Your suite stays green while your users see a broken page.

Driftstack sessions run a browser built from Apple's WebKit source — the engine family behind iPhone Safari, checked against real iPhones. The rendering, the JavaScript timing and the quirks all come from that engine, not from a desktop browser in a phone-sized window. So rendering and layout problems that come from the engine can show up in your tests, not only on your users' phones. There is no hardware to buy.

Safari's own engine, not a lookalike

Built from Apple's WebKit source code — the engine family behind Safari on every iPhone — not a desktop browser shrunk to phone width

The iPhone models your users carry

7 iPhone models (iPhone 13 → 15 Plus) — 16 device profiles in Safari 26.4–26.6.1; pick one, or get a random one

A fresh session for every test run

Sessions are created for each test run and removed after — nothing to keep running between runs

Your pipeline speaks HTTPS. So do we.

Your build-and-test pipeline — CI — starts a session with one call, gives it a task, and closes it when the run ends. First-party SDKs in TypeScript, Python, and Go, plus a plain HTTPS API any HTTP client can drive. Playwright test fixtures, n8n workflows, plain curl from a cron job. The snippet below is the whole session lifecycle.

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

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

// Every session goes out through one of your saved proxies.
let session = await ds.agentSessions.create({ proxy_id: process.env.DRIFTSTACK_PROXY_ID! });

try {
  // Wait up to two minutes for its browser to start.
  for (let i = 0; session.ready === false && i < 60; i++) {
    if (session.status === 'closed') throw new Error('The session did not start');
    await new Promise((resolve) => setTimeout(resolve, 2_000));
    session = await ds.agentSessions.get(session.id);
  }

  // Say what you want. The AI plans the steps and runs them;
  // the call returns when its turn ends.
  const reply = await ds.agentSessions.message(
    session.id,
    'Open https://books.toscrape.com, go to the Travel category ' +
      'and tell me the cheapest book there and its price.',
    { onStep: ({ index, result }) => console.log('step', index + 1, result.kind) },
  );

  // A turn that stops early (a limit, or a question for you) carries a notice.
  if (reply.kind !== 'plan-executed' || reply.notice !== undefined || reply.answer === undefined) {
    throw new Error('The task did not finish');
  }
  console.log(reply.answer);
} finally {
  await ds.agentSessions.close(session.id);
}

Start an agent session and give it the test as a task in plain words: open the page, walk the flow, tell you what it found. The AI plans the taps and page loads, runs them, and answers; your test asserts on that answer and closes the session in the teardown. The session goes out through one of your saved proxies, so the proxy_id in the create is the internet exit you chose. Every run gets a fresh session — or reuse a persistent profile when a test needs logged-in state that survives between runs. Through the API, a profile snapshot saves that profile's device and name so you can spin up a matching fresh profile later.

Webhooks tell your pipeline when a site throws a challenge. Your own command-line tools can sign in with a browser-approved device code instead of a pasted key.

Sessions are billed on one number: concurrent, meaning how many run at the same time — think browser tabs. Run your suite in parallel up to that limit. On a paid plan the hours you use are not billed (the free trial includes 2 hours of session time in total), and API calls are never billed; the AI agent counts against the credits your plan includes.

Every plan includes the API.

Your pipeline starts sessions from the SDK on any plan. Plans differ by how many profiles run at once, so pick the one that matches how many tests run side by side. The AI agent is on every paid plan too.

See plans and prices →

The 7-day free trial includes the API and the SDKs, so you can click through your pages by hand and point your pipeline at them in the same week.

Green in your tests. Green in iPhone Safari.

Start a free trial, check the rendering by hand, and point your pipeline at it. No card needed.