RewindRewind SDK Docs

Exception Capture SDK Setup

Capture frontend and backend exceptions with RewindRewind's native SDKs, or use Sentry-compatible envelope tooling where an existing Sentry SDK is already installed.

Collector and API Keys

The hosted collector is https://rewindrewind.com. Self-hosted Workers can use their own Worker origin in the same SDK options.

REWIND_ENDPOINT=https://rewindrewind.com
REWIND_API_KEY=rr_xxx_secret
REWIND_BROWSER_API_KEY=rr_xxx_public
REWIND_ENVIRONMENT=production
REWIND_RELEASE=web@1.14.0

Payload Shape

Native SDKs send Sentry-shaped JSON to POST /v1/exceptions and custom product events to POST /v1/events.

{
  "environment": "production",
  "release": "web@1.14.0",
  "platform": "javascript",
  "level": "error",
  "message": "Checkout failed",
  "exception": {
    "type": "TypeError",
    "value": "Checkout failed",
    "stacktrace": [
      { "filename": "app.js", "function": "submitCheckout", "line": 120, "column": 19, "in_app": true }
    ]
  },
  "user": { "id": "user_123", "email": "person@example.com" },
  "tags": { "service": "checkout" },
  "extra": { "cart_id": "cart_123" }
}

Event Capture

Send product, workflow, and audit moments to POST /v1/events.

await rewind.captureEvent("checkout.button_clicked", {
  path: window.location.pathname,
  plan: user.plan,
});
curl https://rewindrewind.com/v1/events \
  -H "Authorization: Bearer $REWIND_API_KEY" \
  -H "Content-Type: application/json" \
  --data '{
    "type": "checkout.button_clicked",
    "environment": "production",
    "release": "web@1.14.0",
    "properties": { "path": "/checkout", "plan": "team" }
  }'

JavaScript Browser Apps

npm install @rewindrewind/sdk
import { initRewind } from "@rewindrewind/sdk/browser";

export const rewind = initRewind({
  endpoint: import.meta.env.VITE_REWIND_ENDPOINT ?? "https://rewindrewind.com",
  apiKey: import.meta.env.VITE_REWIND_BROWSER_API_KEY,
  environment: import.meta.env.MODE === "production" ? "production" : "preview",
  release: import.meta.env.VITE_REWIND_RELEASE,
  tags: { service: "web" },
});

The browser SDK captures window.error and window.unhandledrejection by default.

try {
  await submitCheckout();
} catch (error) {
  await rewind.captureException(error, {
    route: window.location.pathname,
    action: "submit_checkout",
  });
  throw error;
}

await rewind.captureEvent("checkout.button_clicked", {
  path: window.location.pathname,
});

Attach users after login and clear them on logout.

rewind.setUser({ id: user.id, email: user.email });
rewind.setTags({ plan: user.plan });
rewind.setUser(undefined);

Sentry Browser Tooling

If a browser app already uses Sentry, keep the SDK and tunnel event envelopes through RewindRewind.

npm install @sentry/browser
import * as Sentry from "@sentry/browser";

Sentry.init({
  dsn: "https://rewind-public@rewindrewind.com/1",
  tunnel: `https://rewindrewind.com/v1/sentry/envelope?sentry_key=${encodeURIComponent(
    import.meta.env.VITE_REWIND_BROWSER_API_KEY,
  )}`,
  environment: import.meta.env.MODE === "production" ? "production" : "preview",
  release: import.meta.env.VITE_REWIND_RELEASE,
});

The tunnel endpoint currently ingests Sentry envelope items with "type": "event". Use native SDKs when you also want RewindRewind product events.

Node.js Apps

npm install @rewindrewind/sdk
import { initRewind } from "@rewindrewind/sdk/node";

export const rewind = initRewind({
  endpoint: process.env.REWIND_ENDPOINT ?? "https://rewindrewind.com",
  apiKey: process.env.REWIND_API_KEY!,
  environment: process.env.REWIND_ENVIRONMENT ?? "production",
  release: process.env.REWIND_RELEASE,
  tags: { service: "api", runtime: "node" },
  autoCapture: true,
});

autoCapture: true captures uncaughtException and unhandledRejection. Capture route and job boundaries explicitly so request metadata is preserved.

app.use((err, req, _res, next) => {
  void rewind
    .captureException(err, {
      request: { method: req.method, url: req.originalUrl },
    })
    .finally(() => next(err));
});

Bun Apps

bun add @rewindrewind/sdk
import { initRewind } from "@rewindrewind/sdk/bun";

const rewind = initRewind({
  endpoint: Bun.env.REWIND_ENDPOINT ?? "https://rewindrewind.com",
  apiKey: Bun.env.REWIND_API_KEY!,
  environment: Bun.env.REWIND_ENVIRONMENT ?? "production",
  release: Bun.env.REWIND_RELEASE,
  tags: { service: "edge-api", runtime: "bun" },
});

Bun.serve({
  async fetch(req) {
    try {
      return await handleRequest(req);
    } catch (error) {
      await rewind.captureException(error, {
        request: { method: req.method, url: new URL(req.url).pathname },
      });
      return new Response("Internal Server Error", { status: 500 });
    }
  },
});

Ruby Apps

gem install rewind_rewind
require "rewind_rewind"

REWIND = RewindRewind::Client.new(
  api_key: ENV.fetch("REWIND_API_KEY"),
  endpoint: ENV.fetch("REWIND_ENDPOINT", "https://rewindrewind.com"),
  environment: ENV.fetch("RACK_ENV", "production"),
  release: ENV["REWIND_RELEASE"],
  tags: { service: "web", runtime: "ruby" }
)
begin
  charge_customer(customer_id)
rescue => error
  REWIND.capture_exception(error, {
    action: "charge_customer",
    customer_id: customer_id
  })
  raise
end

Rack apps can wrap the application with REWIND.rack.call(app). Background jobs can use REWIND.job_wrapper(queue: "critical").

Python Apps

A Python package is not published yet. Until then, send RewindRewind-native JSON with a small helper around urllib.request.

from rewind_rewind import rewind

try:
    process_invoice(invoice_id)
except Exception as error:
    rewind.capture_exception(error, {"invoice_id": invoice_id})
    raise

rewind.user = {"id": user.id, "email": user.email}
rewind.capture_event("invoice.paid", {"invoice_id": invoice.id, "total": invoice.total})

Flask

Connect got_request_exception and capture the exception with method and path metadata.

Django

Add middleware with process_exception near the top of MIDDLEWARE.

FastAPI and ASGI

Wrap the ASGI app and capture exceptions before re-raising.

Direct HTTP Capture

curl https://rewindrewind.com/v1/exceptions \
  -H "Authorization: Bearer $REWIND_API_KEY" \
  -H "Content-Type: application/json" \
  --data '{
    "environment": "production",
    "release": "api@1.0.0",
    "platform": "custom",
    "level": "error",
    "message": "Example failure",
    "exception": { "type": "ExampleError", "value": "Example failure", "stacktrace": [] },
    "tags": { "service": "api" },
    "extra": { "source": "curl" }
  }'

Sentry Envelope Endpoint

Send Sentry event envelopes to POST /v1/sentry/envelope. Authenticate with Authorization: Bearer rr_xxx or ?sentry_key=rr_xxx.

curl "https://rewindrewind.com/v1/sentry/envelope?sentry_key=$REWIND_API_KEY" \
  -H "Content-Type: application/x-sentry-envelope" \
  --data-binary @envelope.txt

Source Maps

Upload JavaScript source maps with a backend server_secret key and use the same release value as the browser SDK.

curl https://rewindrewind.com/v1/source-maps \
  -H "Authorization: Bearer $REWIND_API_KEY" \
  -H "Content-Type: application/json" \
  --data-binary @- <<'JSON'
{
  "release": "web@1.14.0",
  "file_name": "assets/app.js.map",
  "content": "..."
}
JSON

Verification Checklist

  1. Trigger a handled test exception in every runtime.
  2. Trigger an unhandled browser exception and unhandled promise rejection.
  3. Trigger an unhandled backend exception in a non-production environment.
  4. Confirm events land in the intended project and environment.
  5. Send the same exception twice and confirm issue grouping.
  6. Confirm release, service, and runtime tags are present.
  7. Confirm browser requests are rejected from disallowed origins.
  8. Confirm no server key is present in built frontend assets.
  9. Upload a source map and verify stack frames resolve for that release.

Operational Guidance

The repository also includes the longer Markdown guide at docs/exception-capture-sdk.md for maintainers.