Skip to content

mimeticinc/rerun

Find the friction users hit before they tell you

Open-source session replay you can run on your own infrastructure.

Rerun records real browser sessions to your server, turns them into concise friction reports, and gives your team the context to debug broken flows faster.

Built on rrweb. Designed for teams that want the useful part of hosted replay tools without sending every session to another analytics vendor by default.

Why Use It

  • Debug real sessions: see the clicks, pages, errors, and dead ends behind support tickets and churn.
  • Own the data path: store replays in your own Cloud Run, S3, GCS, or local environment.
  • Skip manual replay review: turn long session timelines into short reports with evidence and timestamps.
  • Catch UX failures logs miss: rage clicks, confusing navigation, broken flows, stuck forms, and unclear CTAs.
  • Start local, ship later: run the collector locally, capture a session, and analyze it from the CLI in minutes.

Quickstart

Start the local collector, then add the SDK to an app and inspect the recording.

npm install @mimeticinc/rerun
npx @mimeticinc/rerun quickstart

The command pulls ghcr.io/mimeticinc/rerun-server:latest, starts the local ingest server, and prints a local ingestBaseUrl, generated publicKey, generated readKey, and generated adminKey.

In your app:

import { init } from "@mimeticinc/rerun";

const replay = init({
  appId: "my-app",
  publicKey: "public_replay_...",
  ingestBaseUrl: "http://127.0.0.1:8787",
});

// Call only after your cookie banner or privacy control grants analytics consent.
replay.optIn({ source: "cookie-banner", version: "2026-05-05" });

Use the app normally, then inspect what happened:

npx @mimeticinc/rerun replays --read-key read_replay_...
npx @mimeticinc/rerun analyze --latest --read-key read_replay_...

To ask Claude to review the redacted narrative from your local machine:

ANTHROPIC_API_KEY=sk-ant-... \
  npx @mimeticinc/rerun analyze --latest --llm --confirm-external-llm-export

Or use OpenAI:

OPENAI_API_KEY=sk-... \
  npx @mimeticinc/rerun analyze --latest --llm --llm-provider openai --confirm-external-llm-export

The collector stores and summarizes replays. External LLM calls happen from your local CLI, using your local API key.

Stop the collector:

npx @mimeticinc/rerun stop

Install

From npm after package publication:

npm install @mimeticinc/rerun

From GitHub before npm publication:

npm install github:mimeticinc/rerun

Local Collector

The default local CORS allow-list covers Vite on 5173 and CRA/Next on 3000. For another dev port:

npx @mimeticinc/rerun quickstart --cors-origin http://localhost:4200

To pin or test a different collector image:

npx @mimeticinc/rerun quickstart --server-image ghcr.io/mimeticinc/rerun-server:v0.1.0

When developing from a source checkout, build and run the local server directory instead of the published image:

git clone https://github.com/mimeticinc/rerun.git
cd rerun
npm install
npm run quickstart

If you want to use the installed CLI with a source checkout, pass the server path:

npx @mimeticinc/rerun quickstart --server-dir /path/to/rerun/server

Browser SDK

import { init } from "@mimeticinc/rerun";

const replay = init({
  appId: "my-app",
  publicKey: "public_replay_...",
  ingestBaseUrl: "http://127.0.0.1:8787",
});

// Call only after your cookie banner or privacy control grants analytics consent.
replay.optIn({ source: "cookie-banner", version: "2026-05-05" });

replay.addCustomEvent("checkout_started", { plan: "pro" });

Flush before route transitions, logout, unload flows, or tests:

await replay.flush({ final: true });

If consent has already been granted before initialization, pass consent: "granted".

React

import { SessionReplayProvider, useConsent } from "@mimeticinc/rerun/react";

function CookieBanner() {
  const { grant, deny } = useConsent();

  return (
    <>
      <button onClick={() => grant({ source: "cookie-banner", version: "2026-05-05" })}>
        Accept analytics
      </button>
      <button onClick={() => deny()}>Reject</button>
    </>
  );
}

export function App() {
  return (
    <SessionReplayProvider
      config={{
        appId: "my-app",
        publicKey: "public_replay_...",
        ingestBaseUrl: "http://127.0.0.1:8787",
      }}
    >
      <CookieBanner />
      <Routes />
    </SessionReplayProvider>
  );
}

What Gets Captured

Default capture after consent:

  • Masked rrweb DOM replay events.
  • Custom events you add through addCustomEvent.
  • User/session metadata you explicitly set through identify and tag.

Off by default:

  • Network capture.
  • Request and response body capture.
  • Web Vitals, resource timings, JavaScript errors, and console capture.
  • Behavioral export for training-style interaction streams.

Privacy Defaults

  • Consent defaults to deferred; nothing records until optIn() or setConsent(true).
  • rrweb input and text masking are enabled by default.
  • URL query strings and hashes are stripped by default.
  • Network capture is disabled by default. If enabled, body capture is still disabled unless configured.
  • Common PII patterns are redacted from custom events, tags, traits, errors, resource names, headers, and configured network bodies.
  • The supported ingest server also applies default-on server-side redaction before raw replay batches are stored.
  • Public ingest keys are accepted from SDK headers or bounded JSON bodies, never query strings.

Optional Capture

Network metadata:

init({
  appId: "my-app",
  publicKey: "public_replay_...",
  ingestBaseUrl: "https://collector.example.com",
  network: {
    enabled: true,
    recordHeaders: { request: false, response: false },
    recordBody: ["application/json"],
    bodyMaxBytes: 16_384,
    urlDenyList: [/\/billing\//],
  },
});

Use request/response body capture only for endpoints whose payloads are safe to collect. Prefer privacy.networkBodyAllowPaths, privacy.networkBodyDenyPaths, and privacy.redactPatterns when enabling bodies.

Event filtering:

init({
  appId: "my-app",
  publicKey: "public_replay_...",
  ingestBaseUrl: "https://collector.example.com",
  beforeRecordEvent(event) {
    return JSON.stringify(event).includes("internal-debug") ? null : event;
  },
});

Behavioral export:

init({
  appId: "my-app",
  publicKey: "public_replay_...",
  ingestBaseUrl: "https://collector.example.com",
  behavioral: { enabled: true },
});

Behavioral export is off unless explicitly enabled and has no hosted fallback endpoint.

Self-Hosting

The server/ directory is the supported FastAPI ingest service for replay storage, admin APIs, and friction analysis. The npm quickstart starts the published server image, and the source checkout can build the server directly.

Published Docker image:

docker run --rm -p 8787:8787 \
  --cap-drop ALL \
  --security-opt no-new-privileges \
  --read-only \
  --tmpfs /tmp:rw,noexec,nosuid,size=64m \
  -e PUBLIC_INGEST_KEYS=public_dev_key \
  -e READ_KEYS=read_dev_key \
  -e ADMIN_KEYS=admin_dev_key \
  -e CORS_ORIGINS=http://localhost:5173 \
  -e ENABLE_METRICS=true \
  -e METRICS_REQUIRE_AUTH=true \
  -v rerun-replay-data:/data \
  -v rerun-replay-export:/export \
  ghcr.io/mimeticinc/rerun-server:latest

Local Docker:

cd server
cp .env.example .env
docker compose up --build -d ingest

Python:

cd server
python3 -m venv .venv
. .venv/bin/activate
pip install -e .

PUBLIC_INGEST_KEYS=public_dev_key \
READ_KEYS=read_dev_key \
ADMIN_KEYS=admin_dev_key \
CORS_ORIGINS=https://app.example.com \
uvicorn ingest:app --host 127.0.0.1 --port 8787

Single-tenant Google Cloud Run plus Cloud Storage:

ENV_FILE=deploy/gcp/rerun-cloud-run.env.example deploy/gcp/deploy-cloud-run.sh

The Cloud Run deploy script uses ghcr.io/mimeticinc/rerun-server:latest by default. Set SERVER_IMAGE to pin a version or DEPLOY_FROM_SOURCE=true when testing a local server checkout.

See server/README.md and docs/GCP_CLOUD_RUN.md for production setup.

Production Settings

Required:

  • PUBLIC_INGEST_KEYS: comma-separated browser ingest keys.
  • READ_KEYS: comma-separated keys for listing replays, generating redacted narratives, no-LLM analysis, and MCP.
  • ADMIN_KEYS: comma-separated keys for raw replay export, deletion, stats, and stitching. Admin keys also work for read APIs.
  • CORS_ORIGINS: comma-separated allowed browser origins.

Recommended:

  • MAX_BODY_BYTES: maximum compressed or decompressed request body size. Default 2000000.
  • MAX_EVENTS_PER_BATCH: maximum event count per ingest request. Default 5000.
  • MAX_REPLAY_SEQUENCE: maximum replay batch sequence accepted per session. Default 720; set 0 to disable.
  • SERVER_SIDE_REDACTION=true: scrub common PII and sensitive fields before raw batches are stored.
  • MAX_STORED_STRING_BYTES=16384: cap stored string values after server-side redaction.
  • INGEST_RATE_LIMIT and ADMIN_RATE_LIMIT: basic per-process abuse controls.
  • LOCAL_RETENTION_DAYS: local filesystem retention window. Use bucket lifecycle policies for S3/GCS.
  • ENABLE_METRICS=true: expose Prometheus-style operational metrics at /metrics.
  • METRICS_REQUIRE_AUTH=true: require a read or admin key for /metrics. Set false only behind private-network scrape controls.

Set ALLOW_UNAUTHENTICATED_INGEST=true only for local development.

Operational endpoints:

  • GET /health is unauthenticated and returns process health only.
  • GET /metrics returns content-free counters and gauges such as request counts, accepted ingest batches, accepted event counts, replay-session count, and storage byte counts. It never includes session IDs, URLs, replay events, narratives, public keys, read keys, or admin keys.
  • GET /v1/stats is admin-only and returns storage/stitching details for troubleshooting.

Rerun does not send runtime telemetry back to Mimetic by default. GHCR image pull metadata and npm download counts come from the package registries; npm counts are available after the package is published.

Key creation:

  • Local quickstart generates high-entropy keys on each run and prints the exact SDK and CLI values to use. Pass --public-key, --read-key, or --admin-key only when you need repeatable local test credentials.
  • The Cloud Run deploy script creates production keys with openssl rand when you do not provide them, then stores them in Secret Manager.
  • If the configured Secret Manager secret already exists, the deploy script reuses the existing value. If you set PUBLIC_INGEST_KEY, READ_KEY, or ADMIN_KEY, it writes that value as a new secret version.

CLI Reference

npx @mimeticinc/rerun quickstart
npx @mimeticinc/rerun quickstart --server-image ghcr.io/mimeticinc/rerun-server:v0.1.0
npx @mimeticinc/rerun quickstart --server-dir /path/to/rerun/server
npx @mimeticinc/rerun replays
npx @mimeticinc/rerun analyze --latest
npx @mimeticinc/rerun analyze --session SESSION_ID
npx @mimeticinc/rerun analyze --latest --llm --confirm-external-llm-export
npx @mimeticinc/rerun analyze --latest --llm --llm-provider openai --confirm-external-llm-export
npx --package @mimeticinc/rerun rerun-mcp --url https://YOUR-COLLECTOR-HOST/api/mcp --read-key "$RERUN_READ_KEY"
npx @mimeticinc/rerun smoke --stop-after
npx @mimeticinc/rerun stop

quickstart starts the published server image by default. Pass --server-dir /path/to/rerun/server only when developing against a local source checkout. smoke posts a synthetic replay through the pipeline; use it for CI/plumbing checks, not product insight.

MCP

Install the MCP from npm and point it at any hosted Rerun collector:

claude mcp add --transport stdio rerun -- \
  npx -y --package @mimeticinc/rerun rerun-mcp \
    --url https://YOUR-COLLECTOR-HOST/api/mcp \
    --read-key read_replay_...

For long-lived shared configs, prefer environment variables or your MCP client's secret storage so read keys do not live in shell history or checked-in config. You can also use the remote HTTP endpoint directly when your MCP client supports headers:

claude mcp add --transport http rerun https://YOUR-COLLECTOR-HOST/api/mcp \
  --header "Authorization: Bearer $RERUN_READ_KEY"

The MCP is not project-specific. A teammate needs only the hosted collector URL and a read key; no source checkout or localhost collector is required. Admin keys also work, but read keys are the right default for routine MCP access.

Rerun also includes MCP Registry metadata in server.json under io.github.mimeticinc/rerun. After the npm package is public, maintainers can publish the registry entry with mcp-publisher.

Available tools:

  • list_replays
  • get_replay_summary
  • get_replay_narrative
  • analyze_replay

The MCP uses the same read auth as replay listing and narrative APIs. It returns bounded summaries and redacted CSV narratives, not raw rrweb event batches. See docs/MCP.md.

Development

npm install
npm test
npm run typecheck
npm run build
npm run test:browser
python3 -m py_compile server/*.py
python3 -m unittest discover server/tests

See TESTING.md for the broader browser, privacy, server, mutation, and release testing strategy.

Project Status

This is a 0.1.0 launch candidate. The SDK and ingest server are supported surfaces. It does not yet include a replay viewer, dashboard, multi-tenant admin UI, issue workflow, Slack/Linear routing, or full analytics suite.

Useful docs:

License

MIT

Third-party notices for bundled or runtime dependencies are in THIRD_PARTY_NOTICES.md.

About

Open-source session replay and self-hosted friction reports for debugging real user flows

Topics

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors