Official site: mockifyer.dev — public playground and docs: try record/replay, scenarios, and the interactive demo without cloning this repo. For AI assistants: llms.txt · llms-full.txt. To use Mockifyer in your own app, install the npm packages below (the site is for trying the product, not a hosted backend for your code). Comparing tools? See mockifyer.dev/comparisons for feature comparisons with MSW, Polly.js, Nock, Mirage JS, WireMock, Mockoon, and json-server.
Contact: Sebastian Gedda (@sgedda) — open an issue for bugs and ideas, or a pull request if you already have a change. General GitHub profile: @sgedda.
API mocking and recording for axios and fetch, with date manipulation for tests. Mock data lives in your repo as JSON (per request/response), with optional scenarios and React Native / Expo support. Monorepo for Mockifyer: libraries for mocking and recording API calls, with special support for date manipulation in tests.
Published packages (install these, not the repo root):
@sgedda/mockifyer-core— types, providers,getCurrentDate, etc.@sgedda/mockifyer-axios— Axios integration (setupMockifyer,initMockifyerForDashboardProxy)@sgedda/mockifyer-fetch—fetchintegration (setupMockifyer)@sgedda/mockifyer-dashboard,@sgedda/mockifyer-test-helper— optional tooling
The root package.json is private workspace metadata only (not published). The legacy package is not on npm; on GitHub Packages it appears as pkgs/npm/mockifyer (unscoped name mockifyer in the API). To remove versions: scripts/delete-github-packages-legacy-mockifyer.sh (needs gh + delete:packages).
This repository is a monorepo. Prefer the scoped packages below; the root package.json is legacy workspace metadata.
| Package | Use case |
|---|---|
@sgedda/mockifyer-core |
Types, providers (filesystem, Expo, hybrid, memory), scenarios, date helpers, mock matching |
@sgedda/mockifyer-fetch |
fetch / React Native — setupMockifyer, initMockifyerForDashboardProxy (Node) and initMockifyerForReactNativeDashboard (Expo) for mockifyer-dashboard + Redis |
@sgedda/mockifyer-axios |
Axios — setupMockifyer, initMockifyerForDashboardProxy (Node dashboard + Redis/SQLite proxy) |
@sgedda/mockifyer-dashboard |
Local UI to browse/edit mock-data (optional; separate dev server) |
@sgedda/mockifyer-mcp |
MCP Server — Model Context Protocol integration for Cursor and Claude Desktop (query/modify mocks via natural language) |
Initializing Mockifyer (all entrypoints): MOCKIFYER_INITIALIZATION.md.
Team workflow (recorded vs curated mocks, re-recording): MOCK_WORKFLOW.md.
React Native / Expo: see REACT_NATIVE.md for Hybrid provider, Metro sync middleware, and setupMockifyerForReactNative.
Runtime Toggle: see docs/RUNTIME_TOGGLE.md to enable/disable Mockifyer at runtime (completely bypass dashboard, Redis, and proxy with a button press).
npm install @sgedda/mockifyer-core @sgedda/mockifyer-axios
# or for fetch:
# npm install @sgedda/mockifyer-core @sgedda/mockifyer-fetchAI assistants in your app repo (editor-agnostic):
npx mockifyer-init-aiInstalls docs/mockifyer-ai/ (INSTRUCTIONS.md + reference). Docs ship with @sgedda/mockifyer-core.
Model Context Protocol support for Cursor and Claude Desktop allows you to interact with Mockifyer using natural language:
# Build the MCP server (first time)
cd packages/mockifyer-mcp
npm install && npm run buildThe repository includes a pre-configured .cursor/mcp.json that works out of the box. Start the dashboard and restart Cursor to enable:
- "List all mocks in the default scenario"
- "Override the booking status to CONFIRMED"
- "Create a new scenario from default"
- "Trace the network call that returned 502"
See .cursor/README.md and packages/mockifyer-mcp/README.md for details.
import { setupMockifyer } from '@sgedda/mockifyer-fetch';
import { getCurrentDate } from '@sgedda/mockifyer-core';
setupMockifyer({
mockDataPath: './mock-data',
dateManipulation: {
fixedDate: '2024-01-01T00:00:00.000Z',
},
});
const response = await fetch('https://api.example.com/data');
// Intercepted when setupMockifyer ran (Node); RN uses MOCKIFYER_MODE — see REACT_NATIVE.md
const currentDate = getCurrentDate();
console.log(currentDate.toISOString()); // 2024-01-01T00:00:00.000Zimport { setupMockifyer, getCurrentDate } from '@sgedda/mockifyer-axios';
setupMockifyer({
mockDataPath: './mock-data',
dateManipulation: {
fixedDate: '2024-01-01T00:00:00.000Z',
},
});
const response = await axios.get('https://api.example.com/data');Date manipulation: use getCurrentDate() from the same package you use for setupMockifyer instead of new Date(), so fixed date / offset / timezone apply. With the dashboard Redis/SQLite proxy, that call follows the active scenario’s Date Config (a client-lane date wins). Switch scenarios or update the date in the dashboard and getCurrentDate() tracks it — no extra arguments.
- Record and replay HTTP requests (axios or fetch)
- Automatic interception driven by env + config
- Scenarios —
mock-data/<scenario>/...plusscenario-config.json - Date manipulation (fixed date, offset, timezone) for tests
- Status override — simulate error responses (500, 429, 404) without modifying stored response data
- Response delay — add artificial latency to test slow network conditions
- Easy discovery — JSON files in the repo (searchable in your IDE)
- React Native — device storage + optional Metro sync to keep repo and simulator in sync (REACT_NATIVE.md)
Recorded mocks are stored as JSON (nested under mock-data/<scenario>/ when scenarios are used). Each file typically includes:
- Request: method, URL, headers, query params, body
- Response: status, body, headers
- Metadata: timestamp, optional
scenario
File layout on disk often mirrors host and path (e.g. api.example.com/rest/.../GET_identifier_timestamp.json). See packages for exact naming rules (file-naming utilities in core).
Same ideas as before: fixedDate, offset, timezone in setupMockifyer, or env vars:
export MOCKIFYER_DATE="2025-01-01T00:00:00Z"
export MOCKIFYER_DATE_OFFSET="86400000"
export MOCKIFYER_TIMEZONE="America/New_York"Priority: env vars → setupMockifyer config → system time.
Scenario dates: Date manipulation from a scenario's date-config.json (or dashboard Date Config) applies only when a named scenario is active (e.g. default, checkout). Traffic under _scratch (the temporary unscoped bucket) always uses real time. When you switch scenarios, getCurrentDate() never serves the previous scenario's date — it returns real time until the new scenario's date config is loaded.
| Variable | Description |
|---|---|
MOCKIFYER_MODE |
React Native startup: on | manual (aliases: gui, toggle) | launch_client | off (see MockifyerRuntimeMode in core; unset defaults to on). manual mode patches fetch but starts disabled; call enableMockifyer() to activate (pair with persistRuntimeEnabled: true to save the choice). launch_client activates on a launch mockifyerClientId OR scenario. See docs/RUNTIME_TOGGLE.md for runtime enable/disable API. |
MOCKIFYER_DOMAIN_PATH_RULES_MODE |
Hybrid/filesystem: allowlist (default) | record_all | off — auto-discovers host/path keys into domain-path-rules.json; gates record + replay (see Domain-path rules below for allowUpstream). Migration: set record_all or off if you relied on ungated recordMode |
MOCKIFYER_RECORD |
Record real responses (fetch/axios packages); with initMockifyerForDashboardProxy, implies recordOnMiss: true when not otherwise set |
MOCKIFYER_PROXY_RECORD_ON_MISS |
Fetch + proxy.baseUrl: when proxy.recordOnMiss is omitted, true / false sets the record flag on /api/proxy; omit env to defer to dashboard per-scenario "Record on miss" |
MOCKIFYER_RECORD_DEFAULT_ALWAYS_USE_REAL_API |
When not false, new recordings (proxy Redis, fetch/axios disk) set alwaysUseRealApi: true so the response is stored but live API is used until you uncheck in the dashboard. Set to false for legacy "replay mock immediately after capture" behavior |
MOCKIFYER_RECORD_NEW_AS_PASSTHROUGH |
New recordings get alwaysUseRealApi (visible in dashboard, live API until activated) |
MOCKIFYER_REFRESH_PASSTHROUGH_RECORDINGS |
Update passthrough mock files in place on each live API response |
MOCKIFYER_PATH |
Mock data root (legacy name; often mockDataPath in config) |
MOCKIFYER_SCENARIO |
Active scenario name |
MOCKIFYER_STRICT_SCENARIO |
true/… — fetch/RN dashboard-proxy mode: bypass Mockifyer until clientId or proxy.scenario is set (requires proxy.baseUrl) |
MOCKIFYER_STRICT_LANE_SCENARIO |
Lane-only proxy scenario: no global/filesystem fallback when clientId is set and lane mapping is missing. Default true on dashboard and in SDK when proxy.baseUrl is set. Set false or proxy.strictLaneScenario: false in init to allow global fallback. SDK sends strictLaneScenario on each proxy POST. |
MOCKIFYER_LANE_GLOBAL_FALLBACK |
Dashboard (redis/sqlite): true makes clients with a clientId but no lane follow the global scenario even in strict lane mode. Default for the setting toggled by PUT /api/client-lanes/settings/global-fallback; the stored setting wins. Default false |
MOCKIFYER_USE_SIMILAR_MATCH |
Path-based fallback matching |
MOCKIFYER_USE_SIMILAR_MATCH_CHECK_RESPONSE |
Verify response when similar-matching |
MOCKIFYER_ACTIVATION_MODE |
always | client_id_header | off — when interceptors run (overrides activationMode in config) |
MOCKIFYER_MAX_REQUESTS_PER_SCENARIO |
Max mocks per scenario (filesystem and Redis). Unset = no scenario cap |
MOCKIFYER_MAX_MOCKS_PER_PATH |
Max distinct Redis mocks per METHOD+host+pathname (default 200). Set 0/off to disable. Stops high-cardinality POST floods |
MOCKIFYER_ECHO_TRACE_ID |
When false/0/off/no, skip echoing X-Mockifyer-Request-Id on HTTP responses from Node inbound capture (default on) |
MOCKIFYER_AUTO_INBOUND_CORRELATION |
When false/0/off/no, skip installing Node inbound hop capture on setupMockifyer (default on) |
See @sgedda/mockifyer-core ENV_VARS and package READMEs for the full set.
The client ID (also called lane ID) identifies which client or test session is making requests. Used with the dashboard proxy to isolate mocks per client, and with strict lane mode to control whether traffic uses mocks or goes to live API.
Client ID is resolved in the following order:
| Priority | Source | Platforms | Notes |
|---|---|---|---|
| 1 | MOCKIFYER_CLIENT_ID env var |
All | Build-time configuration |
| 2 | EXPO_PUBLIC_MOCKIFYER_CLIENT_ID env var |
Web only (Expo) | Embedded in web bundle at build time |
| 3 | URL query parameter ?mockifyerClientId=... |
Web only | Runtime override, persisted to localStorage |
| 4 | localStorage['mockifyer-client-id'] |
Web only | Persistent across sessions |
| 5 | config.clientId |
All | Passed to setupMockifyer / setupMockifyerForReactNative |
| 6 | MOCKIFYER_CLIENT_LANE env var |
All | Precomputed lane identifier |
| 7 | Build metadata | All | Computed from MOCKIFYER_APPLICATION_ID, MOCKIFYER_MARKET, MOCKIFYER_VERSION_NAME, MOCKIFYER_VERSION_CODE |
Web-specific features (v1.10.191+):
- Expo public env var: Set
EXPO_PUBLIC_MOCKIFYER_CLIENT_ID=your-laneat build time - URL parameter: Navigate to
http://localhost:3000?mockifyerClientId=test-laneto override the client ID for that session (automatically persisted to localStorage) - localStorage: URL parameters are saved to localStorage and reused in future sessions
Native platforms (iOS/Android) can also use launch arguments via react-native-launch-arguments for E2E testing with Maestro/XCTest.
| Priority | Source |
|---|---|
| 1 | MOCKIFYER_SCENARIO env |
| 2 | MockifyerConfig.defaultScenario or scenarios.default ( defaultScenario wins when both are set ) |
| 3 | scenario-config.json (preferred: scenario-config.{clientId}.json when that file exists ) |
| 4 | _scratch — temporary unscoped bucket (not the named default scenario) |
When nothing is set, traffic uses _scratch. Redis mocks under _scratch expire after 24h (override with MOCKIFYER_SCRATCH_SCENARIO_TTL_SEC). Select or set a named scenario (including default) for durable mocks. The dashboard labels _scratch as Temporary (unscoped).
Per proxied request: scenario in the POST body (client override) → client_scenario:{clientId} → Redis active_scenario → filesystem seed via getCurrentScenario on the dashboard.
With strict lane (default when using the dashboard proxy): non-empty clientId plus missing client_scenario:{clientId} ⇒ upstream passthrough only (no global active_scenario). Configure per app via proxy.strictLaneScenario in setupMockifyer / setupMockifyerForReactNative (overridable with MOCKIFYER_STRICT_LANE_SCENARIO env).
To let the header Scenario picker move such clients without creating a lane, turn on the dashboard's opt-in lane global fallback: PUT /api/client-lanes/settings/global-fallback with { "enabled": true } (or start the dashboard with MOCKIFYER_LANE_GLOBAL_FALLBACK=true). A missing lane then resolves to active_scenario with resolutionSource: "global_fallback"; existing lanes still win. GET /api/client-lanes reports the current value as laneGlobalFallback.
Android emulators reach the host via 10.0.2.2 (AVD) or 10.0.3.2 (Genymotion). Those addresses are meaningless on the host, so /api/proxy rewrites them to 127.0.0.1 before matching, recording, and fetching upstream. Point the app's dashboard URL at http://10.0.2.2:3002 as usual; you do not need a host-side rewrite of the API URL.
For optional app escape hatches (proxy.scenario SDK / proxy body scenario), last seen resolved in the Client Lanes UI can diverge from the configured lane scenario.
Use activationMode on setupMockifyer(...) (or env MOCKIFYER_ACTIVATION_MODE) to control whether each outbound request goes through mock lookup and recording. Env wins over config when set to a valid value.
| Mode | Behavior |
|---|---|
always (default) |
Same as before: every request uses Mockifyer, subject to excludedUrls and built-in bypasses (e.g. Mockifyer Metro sync URLs). |
client_id_header |
Mockifyer runs only when the outbound request carries a non-empty X-Mockifyer-Client-Id header, or when the inbound request being served (downstream hops inherit it) has the header. Omit the header for a normal real HTTP call; set it (or receive it from an upstream service) to opt that hop into mocks/recording. Requests without the header pass through untouched. |
off |
Interceptors do not apply mock or record behavior; plain HTTP. |
Axios example (header-gated):
import { setupMockifyer } from '@sgedda/mockifyer-axios';
setupMockifyer({
mockDataPath: './mock-data',
activationMode: 'client_id_header',
recordMode: false,
});
// Bypasses Mockifyer (no header)
await axios.get('https://api.example.com/health');
// Uses Mockifyer for this request
await axios.get('https://api.example.com/v1/profile', {
headers: { 'X-Mockifyer-Client-Id': 'ci-lane-eu-1' },
});Fetch example: same activationMode: 'client_id_header' in setupMockifyer from @sgedda/mockifyer-fetch; pass headers: { 'X-Mockifyer-Client-Id': '<lane>' } on fetch calls that should replay or record.
Multi-service flows: have the caller set X-Mockifyer-Client-Id on HTTP requests to a downstream service that runs Mockifyer with client_id_header, so only traffic that is part of the mock/test graph is intercepted.
Dashboard proxy: when the dashboard proxies to the real upstream, it sets X-Mockifyer-Client-Id on that upstream request when a lane clientId is resolved, so downstream APIs can apply the same rule. See MULTI_CLIENT_ISOLATION.md for lane and proxy context.
Implementation helpers (for custom middleware): resolveActivationMode, shouldApplyMockifyer, getOutboundMockifyerClientIdHeader, and MOCKIFYER_CLIENT_ID_HEADER are exported from @sgedda/mockifyer-core.
Domain-path rules (mock-data/<scenario>/domain-path-rules.json) control recording and upstream access on a per-path basis. Each rule includes:
recordResponses: Whentrue, cache misses save full response bodiesautoMock: Whentruewith recording, new mocks replay immediately (noalwaysUseRealApi)allowUpstream: Whenfalse, proxy cache misses return 412 Precondition Failed even if the scenario allows upstream. Whentrue, explicitly re-allow under a blocked parent. When omitted, inherit from the nearest ancestor rule that sets this field, else the scenario default.
Rules use longest-prefix matching: api.example.com/v1/users/:id is more specific than api.example.com/v1 and wins when both exist.
Dashboard: View and edit rules in the Domains view (tree UI) or via POST /api/mocks/domain-path-rules.
React Native: Metro endpoints GET/POST /mockifyer-domain-path-rules (Metro loads project rules onto the device at startup via reloadMockData).
Mock response can be customized at replay time without modifying the stored response data:
Override the HTTP status code to simulate error responses:
{
"request": { ... },
"response": {
"status": 200,
"data": { "message": "success" }
},
"statusOverride": 500
}When statusOverride is set, the mock returns status 500 instead of the stored 200. Useful for testing error handling (e.g., 500, 429, 404).
Dashboard UI: Edit any mock and set "Status Override" in the Response Simulation section.
MCP Tool: mockifyer_set_mock_behavior with statusOverride parameter.
Add artificial latency to test slow network conditions:
{
"request": { ... },
"response": { ... },
"responseDelayMs": 2000
}When responseDelayMs is set, the mock waits 2000ms before returning the response. Useful for testing loading states and timeouts.
Dashboard UI: Edit any mock and set "Response Delay (ms)" in the Response Simulation section.
MCP Tool: mockifyer_set_mock_behavior with responseDelayMs parameter.
Both features can be used together to simulate slow error responses:
{
"statusOverride": 503,
"responseDelayMs": 5000
}Combine Mockifyer (HTTP + dates) with Sinon for spies/stubs on your own code: Testing with Sinon.
Issues and pull requests are welcome — use the Contact links at the top of this README (Issues, PRs).
Mockifyer is maintained by Sebastian Gedda (@sgedda). Prefer GitHub Issues and pull requests so discussions stay searchable for everyone.
Mockifyer is the project brand. The MIT License grants permissions for the software in this repository; it does not grant rights to use the name Mockifyer in a way that implies affiliation, endorsement, or an official product without separate agreement.