ScreenshotNeo

BlogEngineering

REST API Playground for Testing Browser Automation

Use Playwright requests, route mocks, or Postman servers to control API behavior in browser tests and verify the right layer.

By the ScreenshotNeo team1 October 20269 min read

A REST API playground helps browser-automation tests prepare server state, inspect outcomes, or supply controlled responses. The right workflow depends on where you need control:

  • Use Playwright APIRequestContext to create data before a page flow or verify backend state afterward.
  • Use Playwright routing or HAR files when the page must receive deterministic responses without calling the live service.
  • Use a Postman mock server when several clients need a hosted endpoint backed by saved request examples.

These workflows are related, but they establish different facts. A direct request exercises an API endpoint. An intercepted response proves how the page behaves for the supplied payload. A hosted mock serves examples to clients outside one test process.

What a REST API playground contributes

In browser automation, a playground is a controlled place to send HTTP requests, inspect responses, and decide whether the browser talks to a real or simulated backend. It can be a request tool inside your test framework, a network interceptor at the page boundary, or a hosted mock service.

Keep the test question explicit:

Question Best fit What it establishes
Can I create or inspect backend state around a UI flow? Playwright APIRequestContext The test issued API requests for setup or postconditions.
Does the page render a known payload correctly? Playwright page.route or HAR mocking The page received the response supplied by the test.
Can several clients reuse endpoint examples? Postman mock server A hosted endpoint served saved collection examples.
Can I run API assertions independently of the UI? Postman collection scripts or direct API tests Requests and assertions ran as an API workflow.

Playwright documents direct HTTP(S) requests through APIRequestContext, browser test setup in its API testing guide, and interception in Mock APIs. Postman documents scripted collections at Test APIs and write scripts and hosted mocks at its mock server overview.

Workflow 1: direct API calls inside a Playwright test

Use direct requests when the browser test needs authenticated setup, a fixture that is awkward to create through the UI, or a server-side assertion after a visible action.

Choose the request context

A request object created from a browser context shares that context’s cookie jar. An isolated request context has separate cookie storage. Choose the shared form when the browser login session should authenticate the API call; choose an isolated context when setup credentials and browser credentials must remain separate.

Runnable TypeScript example

import { test, expect } from '@playwright/test';

test('updates a profile and verifies the API state', async ({ page, context }) => {
  const api = await context.request.newContext({
    baseURL: process.env.API_BASE_URL,
    extraHTTPHeaders: {
      Authorization: `Bearer ${process.env.API_TOKEN}`,
      Accept: 'application/json'
    }
  });

  let userId: string | undefined;
  try {
    const create = await api.post('/test-users', {
      data: { name: 'Browser test user', plan: 'trial' }
    });
    expect(create.ok()).toBeTruthy();
    userId = (await create.json()).id;

    await page.goto(`${process.env.APP_URL}/profile/${userId}`);
    await page.getByLabel('Display name').fill('Updated name');
    await page.getByRole('button', { name: 'Save' }).click();

    await expect(page.getByText('Profile saved')).toBeVisible();

    const check = await api.get(`/test-users/${userId}`);
    expect(check.ok()).toBeTruthy();
    await expect.poll(async () => (await check.json()).name).toBe('Updated name');
  } finally {
    if (userId) {
      const remove = await api.delete(`/test-users/${userId}`);
      expect([200, 202, 204, 404]).toContain(remove.status());
    }
    await api.dispose();
  }
});

Use a dedicated test environment and supply credentials through your CI secret store. Do not hard-code tokens. Cleanup belongs in a finally block so a failed assertion does not leave data behind.

When this is faster and when it is not

Creating state through an API can be more targeted than clicking through every setup screen. That is a workflow implication of Playwright’s documented request capability, not a benchmark. The request still depends on a reachable service, valid test data, authentication, and compatible API behavior.

Workflow 2: intercept and mock requests at the browser boundary

Use routing when the page should receive a known response regardless of the live backend. Playwright can intercept HTTP and HTTPS traffic, including XHR and fetch, then continue, modify, abort, or fulfill a request. HAR files provide a repeatable set of recorded interactions.

Fulfill a JSON response

import { test, expect } from '@playwright/test';

test('renders an empty projects response', async ({ page }) => {
  await page.route('**/api/projects**', async route => {
    await route.fulfill({
      status: 200,
      contentType: 'application/json',
      body: JSON.stringify({ projects: [], total: 0 })
    });
  });

  await page.goto('https://app.example.test/projects');
  await expect(page.getByText('No projects yet')).toBeVisible();
});

Modify only part of a live response

await page.route('**/api/cart', async route => {
  const response = await route.fetch();
  const json = await response.json();
  json.items = json.items.map((item: any) => ({ ...item, price: 0 }));
  await route.fulfill({ response, json });
});

A fulfilled response tests the page’s behavior against the payload you supplied. It does not prove that the live backend returns that payload. Keep a separate live API test for backend correctness.

Use HAR recording and replay

import { test } from '@playwright/test';

test('replays recorded network traffic', async ({ page }) => {
  await page.routeFromHAR('./fixtures/catalog.har', {
    url: '**/api/**',
    update: false,
    notFound: 'abort'
  });
  await page.goto('https://app.example.test/catalog');
});

Record a HAR against a controlled environment, review it for secrets, and commit only sanitized fixtures. An aborted unmatched request is useful because it exposes accidental dependencies instead of silently calling production.

Workflow 3: build a hosted mock with Postman

Postman collections let you save requests and examples, add scripts that assert responses, and run the collection manually or through automation. A Postman mock server exposes saved examples so an application or test client can call a hosted endpoint.

  1. Create an HTTP collection containing the endpoint requests your client needs.
  2. Send each request and save one or more representative examples, including status, headers, and body.
  3. Create a mock server from the collection. The mock selects a saved example based on the incoming request.
  4. Point the browser application’s configurable API base URL at the mock host.
  5. Run the same client tests against success, empty, validation-error, and server-error examples.

Dynamic responses are available when configured, but do not promise arbitrary behavior without defining examples and matching rules. Treat public and private access separately; Postman’s tutorial states that private mocks require an API key.

Example collection test script

pm.test('returns a project list', function () {
  pm.response.to.have.status(200);
  const body = pm.response.json();
  pm.expect(body).to.have.property('projects');
  pm.expect(body.projects).to.be.an('array');
});

A hosted mock is useful when a mobile client, browser app, contract test, and manual tester all need the same examples. It adds setup and access-control work compared with an in-test route handler.

How to choose the workflow

Need Use Check before adopting
Sign in through UI, then inspect server state Context request sharing browser cookies Cookie scope, CSRF requirements, cleanup
Seed data with service credentials Isolated API request context Separate authentication and environment safety
Render a deterministic success or error state page.route or HAR Mock coverage and an independent live API test
Share examples across applications Postman hosted mock Example matching, API keys, public/private exposure
Test the API without a browser Postman collection scripts or direct requests Assertions, retries, data isolation

Edge cases and test design

  • Authentication: decide whether cookies, bearer tokens, client certificates, or custom headers belong to the browser context, API context, or mock client.
  • CSRF: a direct API call may need the same CSRF token and cookie pair that a page obtains during navigation.
  • Eventual consistency: poll a read endpoint with a bounded timeout after a mutation instead of assuming immediate visibility.
  • Pagination: save examples for first page, middle page, empty page, and an invalid cursor.
  • Retries: avoid retrying non-idempotent setup blindly. Use unique test identifiers and server-side idempotency keys where supported.
  • Time and locale: fix timezone and locale in test environments so date formatting does not change snapshots.
  • WebSockets and service workers: HTTP route mocks do not automatically model every non-HTTP channel. Test those paths with the protocol-specific tooling they require.
  • Parallel workers: namespace created records by worker and run identifier, then delete only records owned by that test.

Troubleshooting

Symptom Likely cause Fix
API setup returns 401 Token is missing, expired, or sent to the wrong host. Log the method, URL, and status without logging secrets; verify CI variables and environment base URL.
Browser route never matches Pattern does not include the actual path, query, or origin. Temporarily log requests, then use a precise glob or predicate covering the full URL.
Page shows stale data after setup Read-after-write delay or cached response. Poll with a deadline, invalidate the application cache, or use unique data.
HAR replay aborts unexpectedly An unrecorded request is required by the page. Record the missing dependency, sanitize it, and update the HAR deliberately.
Mock client receives 404 No saved Postman example matches method, path, or headers. Save an example for the exact request and confirm the mock’s matching rules.
Tests pass with mocks but fail against staging The mock hides backend schema, auth, or timing differences. Run a separate live contract or integration suite and compare response schemas.
Cleanup fails after a test error Cleanup is not in a finally hook or uses a different credential. Move deletion to teardown/finally and make cleanup idempotent.

Performance, reliability, and cost

Direct API setup reduces UI actions, which can shorten a test’s path, but network latency and backend load remain. Route and HAR mocks remove service variability and are usually more repeatable, while sacrificing evidence about the live backend. Hosted mocks centralize examples but add a network dependency and access-control configuration.

For reliable suites:

  • Keep fast mocked component flows and a smaller set of live end-to-end flows.
  • Pin response fixtures and review changes as API contract changes.
  • Set explicit request, navigation, and polling timeouts.
  • Capture request IDs and response status in CI logs while redacting credentials.
  • Use disposable test data and deterministic clocks where possible.

Cost is driven by the service you call, CI minutes, and hosted mock usage. Avoid sending load tests through a browser test suite; use an API load-testing tool and an environment designed for it.

Or skip the browser setup

If the goal is to capture a page image or PDF during an automation workflow, ScreenshotNeo provides a single screenshot API request. Its capture pipeline accepts cookie and consent banners, removes more than 60 known consent platforms plus newsletter popups and chat widgets, and lets each cleanup step be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed; response headers identify the page verdict and whether the shot was billed.

See the ScreenshotNeo API documentation for all options.

curl -G "https://api.screenshotneo.com/v1/shot" \
  -d access_key=YOUR_API_KEY \
  --data-urlencode url=https://stripe.com \
  -o shot.webp
import requests

r = requests.get(
    "https://api.screenshotneo.com/v1/shot",
    params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"},
    timeout=90,
)
r.raise_for_status()
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({
  access_key: 'YOUR_API_KEY',
  url: 'https://stripe.com'
});
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot failed: ${res.status}`);
const file = await res.arrayBuffer();
await import('node:fs/promises').then(fs => fs.writeFile('shot.webp', Buffer.from(file)));

The API also supports full-page shots with lazy images loaded, CSS-element capture, dark mode, device presets, custom viewports, retina scale, PDF output, custom CSS and JavaScript, clicks, waits, blocked resources, headers, cookies, user agents, authorization, timezone, geolocation, transparent backgrounds, resizing, caching with a chosen TTL, signed links, asynchronous jobs with signed webhooks, bulk capture of up to 100 URLs per call, a usage API, and an OpenAPI specification. An MCP server exposes take_screenshot, get_page_info, and capture_pdf for Claude, Cursor, and other MCP clients.

Plans include 1,000 shots per month free with no card; paid plans start at $5 for 3,000 shots. Yearly billing gives two months free, and every feature is on every plan. Create a free ScreenshotNeo account.

FAQ

Does a Playwright mock test my backend?

No. It tests the page against the response you supplied. Pair it with a live API or contract test for backend behavior.

Should API setup share browser cookies?

Share the browser context when the API call must use the browser’s session. Use an isolated request context for independent setup credentials.

When is Postman preferable to Playwright routing?

Use Postman when saved examples must be hosted and reused by multiple clients. Use routing when control belongs inside one browser test.

Can one suite use all three workflows?

Yes. A common design seeds data through an API, mocks selected page responses for deterministic UI cases, and runs a smaller live suite against the real service.

How should secrets be handled?

Inject them from CI or a secret manager, redact logs, and use a dedicated test environment. Never commit tokens in code or HAR files.