← All guides

A Polly.JS alternative when the recording needs to be a URL

Honest split first: Polly.JS's core loop still works, and we proved it before writing a word of this page. Netflix's record-and-replay library recorded a real request through Node's https module, wrote a standard HAR 1.2 file to disk, and replayed it offline β€” we even tampered with the saved response body and got the tampered bytes back, so the replay demonstrably never touched the network. 10,000+ GitHub stars and ~200k weekly downloads of @pollyjs/core were earned. And storing recordings as standard HAR instead of a proprietary format is a design decision that ages beautifully β€” more on that below, because it's your eject hatch.

First, the gotchas that send people searching

We verified all of these the week of writing (Aug 2026 β€” @pollyjs/core 6.0.6, adapter-node-http 6.0.6, adapter-fetch 6.0.7, Node 22) β€” every snippet on this page was actually run:

The native-fetch gap, reproduced in 20 lines

This is the one that costs people an afternoon. Same process, same Polly instance, replay mode with recordIfMissing: false:

import { Polly } from '@pollyjs/core';
import NodeHttpAdapter from '@pollyjs/adapter-node-http';
import FSPersister from '@pollyjs/persister-fs';
import https from 'node:https';

Polly.register(NodeHttpAdapter);
Polly.register(FSPersister);

const polly = new Polly('demo-products', {
  adapters: ['node-http'], persister: 'fs', mode: 'replay', recordIfMissing: false,
});

const URL_ = 'https://mockbird.mockbird.workers.dev/m/demo/products?limit=2';

// served from the recording on disk (we tampered with it to prove the point):
const viaHttp = await httpsGet(URL_);          // β†’ "TAMPERED-BY-EDITOR"

// Polly never sees this one β€” it escapes to the real network:
const viaFetch = await (await fetch(URL_)).json();  // β†’ live data

Our actual run printed:

https.get first name : TAMPERED-BY-EDITOR
native fetch first name: Service Name
ESCAPED_POLLY: true

If your codebase (or any dependency) uses native fetch, those calls bypass the recording entirely and hit the real service β€” in CI, on a plane, against production. The fix inside Polly is switching to adapters: ['fetch'] and re-recording. The fix outside Polly is making the mock a URL, so it doesn't matter which HTTP client anything uses.

Your recordings are HAR β€” eject one to a hosted mock in one curl

Polly's persister-fs writes standard HAR 1.2 (creator: "Polly.JS"). Mockbird imports HAR files directly, so any recording you've already made can become a hosted mock API β€” reachable by curl, browsers, mobile apps, subprocesses, teammates, CI:

curl -X POST "https://mockbird.mockbird.workers.dev/api/projects/import?name=polly-eject" \
  -H "content-type: application/json" \
  --data-binary @recordings/demo-products_*/recording.har

We ran exactly that against a recording made minutes earlier: it answered 201 with a live base URL, and GET /m/<project>/products returned the recorded records verbatim β€” now with full CRUD, filtering, pagination and failure injection on top. The JSON responses in the HAR become real, stateful collections. (Full details in the HAR β†’ mock API guide β€” the same import accepts DevTools HAR exports.)

⚑ Prefer clicking to curling? Drop the recording.har at /app#import β€” same result, plus a data browser. No file handy? This link creates a live seeded e-commerce API in one click β€” no signup.

Or record & replay at the URL level β€” Polly's core loop, hosted

Mockbird has record-and-replay built in, but it happens at a URL every client can reach instead of inside one JS process. Point a project's proxy at the real API and turn recording on:

# 1. create a project (no signup)
curl -X POST https://mockbird.mockbird.workers.dev/api/projects \
  -H "content-type: application/json" -d '{"name":"recorded"}'
# β†’ {"id":"<id>","adminKey":"<key>","baseUrl":".../m/<id>", ...}

# 2. proxy unmatched paths to the real API, and record what comes back
curl -X PUT https://mockbird.mockbird.workers.dev/api/projects/<id>/settings \
  -H "x-admin-key: <key>" -H "content-type: application/json" \
  -d '{"proxyBase":"https://jsonplaceholder.typicode.com","proxyRecord":true}'

First request for a path forwards to the upstream and records the 2xx response; every request after that replays the recording locally. The response headers tell you which happened β€” from our verification run:

$ curl -sD - https://mockbird.mockbird.workers.dev/m/<id>/todos/1
x-mockbird-proxied: jsonplaceholder.typicode.com
x-mockbird-recorded: 1          ← first hit: fetched upstream + recorded
{ "userId": 1, "id": 1, "title": "delectus aut autem", "completed": false }

$ curl -sD - https://mockbird.mockbird.workers.dev/m/<id>/todos/1
(no x-mockbird-proxied header)  ← second hit: replayed locally, upstream never touched

Recorded paths show up as routes you can inspect and edit β€” GET /api/projects/<id>/routes listed ours with "recorded": true. And because the replay is just a URL, the simulation flags work on it. Both of these ran against the recorded route above:

curl -i "https://mockbird.mockbird.workers.dev/m/<id>/todos/1?mock_status=503"   # β†’ 503
curl "https://mockbird.mockbird.workers.dev/m/<id>/todos/1?mock_delay=2000"      # β†’ measured 2.25s

That's the drill Polly can't run: replay yesterday's recording and make it fail or crawl on demand, for any client β€” the loading & error states guide has the full recipe set (mock_seq for scripted retry sequences, mock_chaos for probabilistic 5xx storms).

Honest scope note: Mockbird records at route granularity β€” method + path, replayed verbatim. Polly matches on method, URL, headers, body and request order (matchRequestsBy), which is strictly more precise for API-contract testing of request sequences. If you need order-sensitive matching, that's a genuine Polly win.

Or use both β€” they compose

Honest comparison

Polly.JSMockbird
What it isfree OSS record/replay library (JS)free hosted mock API service
Maintenancelast core release Jul 2023; repo quiet since May 2025 (verified via npm/GitHub, Aug 2026)hosted, actively maintained
Reachable fromthe JS process Polly runs inanything with HTTP: curl, browser, mobile, backend, CI, agents
Node native fetchescapes adapter-node-http silently (verified); works via adapter-fetchit's a real URL β€” every client works by definition
Record & replaycore feature; order/header/body matching (more precise)built in: proxyBase + proxyRecord, route-granularity, replayed verbatim
Recording formatstandard HAR 1.2 (credit β€” and importable here)recorded routes, editable in dashboard; exports: db.json/HAR-importable data, OpenAPI, Postman, MSW, types
Recordings portable across HTTP clientsno β€” adapter-specific identifiers; cross-adapter replay crashed (verified)client-irrelevant β€” any client, any language
Stateful CRUD on recorded datano β€” replay onlyyes β€” HAR-imported records become real collections with writes
Error/latency simulationserver route API (intercept), manual?mock_status / ?mock_delay / ?mock_seq / ?mock_chaos on any URL, incl. recorded routes
Works offlineyes (replay mode)no β€” it's a real network call
Latencyzero (in-process)real network latency
Browser supportyes (xhr/fetch adapters), incl. Ember addonyes β€” CORS on by default, it's just a URL
Request capnone10,000/project/day

Written by the Mockbird maker β€” bias disclosed. Where Polly.JS genuinely wins: offline, zero-latency replay with no network flakiness; automatic recording of your real API with full headers preserved; matchRequestsBy precision (method/headers/body/order) that URL-level replay can't match; browser adapters and a first-class Ember integration; standard HAR persistence (a design decision we happily exploit above); and zero request caps. If it still fits your stack and you're comfortable depending on a dormant library, replay tests that run on a plane are a real thing we can't give you. When the recording needs to be a URL β€” for a subprocess, another language, a teammate, a mobile client, or CI against a deployed build β€” that's us.

Full API reference in the docs. More guides: VCR / vcrpy alternative Β· HAR file β†’ mock API Β· nock alternative Β· MSW alternative Β· fetch-mock alternative Β· mock API for Node.js Β· deterministic test data Β· testing loading & error states Β· free mock API tools compared. Create your API β†’