# Rebase documentation > Full documentation for Rebase (https://rebase.dev). Generated from the same source as https://rebase.dev/docs. --- Source: https://rebase.dev/docs/get-started # Install Rebase > Paste one script tag, claim your site, invite the team — from zero to first ticket in minutes. ## Add the script tag Paste this once, just before ``, on every page where the widget should be available: ```html title="index.html" ``` That's the whole install. There is no API key to manage, rotate or leak — your domain identifies your project, and access is enforced by domain ownership and per-user sign-in. The widget never blocks your page: a ~1 KB gzipped loader runs first and only pulls the main bundle (~20 KB gzipped) once your site is set up. Uninvolved sites and unsupported origins load almost nothing. :::note Where it runs Rebase runs on public **HTTPS** domains — production and staging. On localhost the widget explains itself in the console instead of failing silently, so the tag is safe to keep in development. ::: ### Framework placement The embed is the same one line everywhere — only where you put it differs. **Next.js** — use `next/script` so the attributes are preserved: ```tsx title="app/layout.tsx" import Script from "next/script"; export default function RootLayout({ children }) { return ( {children} ``` Per-element controls (`data-rebase-mask`, `data-rebase-block`, `data-rebase-unmask`) and source-attribution hints (`data-rb-source`, `data-rb-component`) live on your own markup — see [What gets captured](/docs/what-gets-captured) and [Source attribution](/docs/source-attribution). ## Content-Security-Policy If your site sends a strict CSP, allow the widget's two origins: ```text title="CSP additions" script-src https://cdn.rebase.dev; connect-src https://api.rebase.dev; img-src data:; ``` The widget renders entirely inside a Shadow DOM host, so it never touches your page's styles and needs no `style-src` exception. Screenshot capture renders your page to a canvas and inherits your page's own `img-src` and `font-src` — cross-origin images your CSP blocks simply come out blank, and `img-src data:` is needed for the captured preview. If capture is fully blocked, the widget retries once and then sends the report **without** a screenshot — element, console and network context still arrive. ## Troubleshooting | Symptom | Likely cause / fix | | --- | --- | | No toolbar appears at all | The site isn't set up for this domain yet — run the claim wizard — or the origin isn't public HTTPS. | | Console says blocked by Content-Security-Policy | Add `cdn.rebase.dev` to `script-src` and `api.rebase.dev` to `connect-src`. | | Sign-in code never arrives | The email isn't an invited member, or it's in spam. An owner can re-send the invite from Settings. | | Members can file tickets but can't resolve them | Expected — only owner and team roles can resolve. | | Sign-in drops after a reload | `localStorage` is blocked (private mode or storage partitioning), so the session can't persist. | | Screenshots come out blank or partial | Cross-origin images blocked by your CSP/CORS during canvas capture — the report still sends. | | Reports fail on a flaky connection | The widget holds the draft and auto-retries when the browser comes back online. | ## Locked out? Ownership recovery uses the same domain proof as setup: verify the meta tag, then a 3-day window opens during which the current owner is notified and can dispute with one click. If nobody disputes, ownership transfers. --- Source: https://rebase.dev/docs/what-gets-captured # What gets captured > The buffers, the timeline, the screenshot, the masking — exactly what a report contains, and what can never leave the page. Every report carries the evidence an engineer needs to reproduce the problem — collected in the browser, bounded by construction, and masked before it ever enters memory. This page is the complete inventory. ## The four buffers Capture is a set of small, fixed-size rolling buffers fed by passive listeners. Memory use doesn't grow with session length, and nothing leaves the page until a member submits a report. | Buffer | Size | What's in it | | --- | --- | --- | | User actions | last 50 | Clicks, typing (masked), form submits, key presses, navigations. Typing is debounced (250 ms), so one entry per burst. | | Console | last 50 | `console.error` and `console.warn` output, uncaught exceptions, unhandled promise rejections. | | Network | last 50 | URL, method, status, duration, and whether it was `fetch` or `XHR`. Rebase's own API traffic is excluded. | | Device snapshot | once | Taken at submit time only — never continuously. | :::note No session replay There is no session video, no DOM replay and no keystroke log. Capture is a bounded rolling buffer merged into a session timeline — not a recording of your users. ::: ## The causal timeline Actions, errors and failed requests are merged into one time-ordered story: **Clicked "Save" → POST /orders returned 500 → TypeError follows**. That's what your team — and the AI — reads, instead of four separate log dumps. The timeline also flags what logs can't show: - **Dead clicks** — a click that produced no navigation, no request and no visible change within a second is flagged. "The button does nothing" arrives with proof. - **Rage clicks** — repeated clicks on the same target in a short window are collapsed and labelled. - **Reload survival** — the tail of the session (last 15 actions + last 10 errors) persists across page reloads, with a page-load boundary in the timeline. If the crash caused the reload, the evidence isn't lost. ## Network capture, in detail Failed requests are classified by **failure kind**, not just status code: HTTP error, timeout, aborted, offline, or blocked (ad-blocker/CORS). Rebase is **GraphQL-aware**: requests to GraphQL endpoints are named by operation (query or mutation + name), and responses that return HTTP 200 but carry an `errors` array are caught as failures — the classic invisible GraphQL bug. What never travels: - **Response bodies — never.** There is no configuration that captures them. - **Request bodies — opt-in only**, via `data-capture-bodies="true"` on the script tag. - Captured URLs lose their query strings and credentials. - Console and network entries are swept for known secret shapes before submission — bearer tokens, `sk_` and `pk_` keys, GitHub/Slack/Google/npm tokens, JWTs, AWS key ids, `password=` and `token=` pairs — and the API sweeps again server-side. ## The element, in depth For the clicked element, Rebase records: tag, id, classes, attributes, ARIA role and label, visible text (truncated to 500 characters, masked), a serialized snippet of its markup (truncated to 4 KB, masked), its size and position, computed styles (display, position, color, background, font, z-index, overflow, opacity, transform, visibility), and an ancestor breadcrumb up to 8 levels deep. Where possible, the element is also attributed to a **framework component and a file:line** — see [Source attribution](/docs/source-attribution). ## The screenshot A viewport-only PNG is taken at the moment of the click — no browser extension, no screen-share permission; it's just the script tag. The widget's own UI is filtered out of the shot, and masked fields are masked in the screenshot too. Server-side, screenshots are re-encoded (stripping anything that isn't pixels), capped at 5 MB, served via short-lived signed URLs (10 minutes), and deleted after 90 days. ## The device snapshot Captured once, at submit: browser and OS, viewport, screen size and pixel density, language, timezone, connection quality, device memory and cores, page URL and referrer. ## Pins that survive change Reports are pinned to the **element** they're about, not a coordinate. Each pin stores four selector strategies (test id, element id, CSS path, structural path) plus a fractional offset inside the element and an absolute-coordinate fallback. On resize, scroll or layout shift the pin follows its element; if the DOM has changed so much that no selector matches, the pin degrades to a **ghost marker** at the original spot instead of lying. ### Route groups Pins match by route group, with query and hash ignored. Obviously-dynamic path segments — pure numbers, UUIDs, long hex ids, ULIDs — are collapsed, so a ticket filed on `/orders/123` pins `/orders/456` too. Static segments (slugs, words) are never collapsed; the grouping is deliberately conservative and runs server-side. The ticket's stored pathname stays the exact page it was filed on, so deep links are unaffected. ## Masking & redaction **Everything typed is masked by default.** Input values are replaced with `•` characters before they enter the capture buffer — they don't exist anywhere to leak. You opt fields *out* of masking, not into it. Some fields can **never** be captured, with no configuration that overrides it: password inputs, credit-card fields (`autocomplete` containing `cc-`), and current-password, new-password and one-time-code autocomplete fields. Your controls, from broadest to narrowest: | Control | Where | Effect | | --- | --- | --- | | `data-mask=".secret, [data-acct]"` | script tag | Masks everything matching the selector list. | | `data-rebase-mask` | any element | Masks that element's value and text. | | `data-rebase-block` | any element | Drops the entire subtree from capture. | | `data-rebase-unmask` | any element | Re-enables a safe field inside a masked subtree. | Rebase also honors the masking you've already set up for other tools: Hotjar (`data-hj-suppress`), FullStory (`fs-mask` / `fs-unmask`), Sentry (`data-sentry-block`) and PostHog markers are respected automatically. Defense in depth: captured payloads are scrubbed a second time on ingest, and [AI triage](/docs/ai-triage) only ever sees a size-budgeted, scrubbed slice — never the raw payload. ## Who sees capture data Capture context (console, network, steps, environment) is visible to **owner** and **team** roles only. Commenters can file and discuss; viewers are read-only. Capture runs on every visitor session of a set-up site, but filing a report requires sign-in. --- Source: https://rebase.dev/docs/source-attribution # Source attribution > How tickets carry a suspected file:line out of the box, and two optional ways to make it exact in production. When a ticket lands, Rebase tries to answer "where is this bug in the code?" and writes the result — a **suspected source location** like `src/components/Checkout.tsx:142 in handleSubmit` — into the ticket, into any tracker issue it creates, and into what [coding agents read over MCP](/docs/mcp). ## What works with zero setup Out of the box, Rebase combines three signals: - **Stack traces**, symbolicated server-side against your bundle's sourcemap *when one is publicly reachable* — a `sourceMappingURL=` comment or a `SourceMap` header on the bundle URL. - **Your connected GitHub repository** (if the [GitHub integration](/docs/github) is on): captured paths, component names, `data-testid` values, element ids and button text are matched against the repo tree to produce commit-pinned file and line permalinks. - **Framework internals** where they survive production: React component names, Vue component files, Svelte dev metadata. Attribution is best-effort by design. When neither a sourcemap nor a repo match is available, the ticket simply ships without the section — everything else is unaffected. ## Making it exact in production Both options are optional; either one sharpens attribution to file-and-line precision. ### Option 1 — publish your sourcemaps Serve your sourcemaps where the Rebase symbolicator can fetch them over HTTPS (public, or behind your CDN). Rebase fetches the bundle named in the stack frame, follows its `sourceMappingURL`, and caches the result — your map is probed at most once a day per bundle. This is also what [Detected issues](/docs/detected-issues) uses: recurring errors get symbolicated stacks from their second occurrence. ### Option 2 — emit source hints at build time Stamp `data-*` attributes on your components' root elements. They survive minification and need no public sourcemaps. Rebase reads, on the element or any ancestor: | Attribute | Value | | --- | --- | | `data-rb-source` (or `data-source`) | `path/from/repo/root.tsx:line` — a column suffix is accepted too. | | `data-rb-component` (or `data-component`) | A component name. | | `data-sentry-component` | Understood as-is if you already use Sentry's bundler plugins. | In development you often get this for free: React's classic JSX transform in development mode and Svelte's dev mode already emit the metadata. For production, any small bundler plugin that stamps `data-rb-source` on component roots is enough. ## Where the suspicion shows up - On the ticket, as the **suspected source** line in the Debug view. - In the body of the GitHub, Linear, Jira or Asana issue Rebase files. - In `get_ticket` responses over [MCP](/docs/mcp) — so an agent starts at the right file instead of grepping. --- Source: https://rebase.dev/docs/ai-triage # AI triage > What triage writes on every ticket, how credits work, and why running out never blocks your pipeline. Every report arrives pre-worked: summarized, classified, and pointed at code — generated right after capture, before anyone opens the ticket. ## What triage writes - **A plain-English summary** with reproduction steps and a severity — low, medium or high — with a confidence score. - **A classification**: bug, change request, question, or other. Downstream formatting adapts — change requests are never framed as defects. - **From → to extraction** for change requests: the AI pulls out exactly what should change and to what, preserving the original strings verbatim so you can search for them. - **A suggested title** — but only when the reporter didn't write one. A derived title gets replaced; a human-written title is never touched. - **A suspected source location** — see [Source attribution](/docs/source-attribution). Summaries are written in English regardless of the report's language, but quoted UI strings and error messages stay in their original language so they remain searchable. ## Summaries that link to evidence Sentences in the summary are clickable: "POST /orders returned 500" opens that exact network entry, "TypeError follows" opens that console line, and file references point at the file and line. The summary is a map of the capture, not a paraphrase of it. ## Duplicate detection Tickets are embedded semantically and matched against the last 90 days. Near-duplicates (0.86 cosine similarity) are marked and linked to the canonical ticket, and the canonical tracker issue gets a cross-reference comment so related reports stay visible from the original issue. Duplicates are **detected and linked** — your queue stays a list of problems, not a list of complaints. ## Credits Simple metering, no surprises: | Fact | Value | | --- | --- | | 1 credit | 1 AI-triaged ticket | | Included | 200 credits per project, per month | | Free forever | Semantic search, duplicate matching, embeddings | | Meter | Live usage meter in Settings | | Notices | Owner emails at 80% and 100% | | Failures | Credits are refunded if the model call fails | A **no-signal gate** runs before the model does: reports with nothing to work with are detected early, so empty reports never burn a credit. :::note Fails open, never blocks If a project is out of credits or the model errors, the ticket still flows to your tracker un-enriched. Triage is an accelerant, not a dependency. ::: ## Re-running triage Owners and team members can re-run the AI on any ticket — after a failure, or once credits refill. Re-triage regenerates the summary only; it never re-creates tracker issues or duplicate comments, and it costs one credit like a normal run. ## The Debug view Any ticket thread morphs into a Debug panel: the AI triage on top, tabs for steps, console, network and environment underneath, and the suspected source — in the widget, on the page. There is no separate dashboard to open. ## What the AI sees Triage reads a scrubbed, size-budgeted slice of the capture — never the raw payload, and never anything that was [masked at the source](/docs/what-gets-captured). Your data is never used to train models. --- Source: https://rebase.dev/docs/detected-issues # Detected issues > Opt-in error detection from real visitor sessions — grouped, trended, and gated behind a human review queue. Detected issues catches the bugs nobody reports: opt in, and Rebase auto-collects uncaught exceptions and unhandled promise rejections from everyone browsing your site — including the users who would never click "report". ## Off by default, opt-in per project Proactive detection is **off** until an owner turns it on, per project, in Settings. Once enabled it runs on every visitor session. ## A review queue, not ticket spam Detected errors land in a **staged queue** — not your ticket list, and not your tracker. Nothing becomes a ticket until a human promotes it. Your tracker only ever sees what you chose to send it. ## Grouped, counted, trended Errors are fingerprinted and collapsed, so the queue stays a list of distinct problems: - One row per distinct error, with an occurrence count, first and last seen, and how many sessions were affected. - A 14-day daily trend per group, so you can see whether it's growing. - Grouped across pages: the same error on five routes is **one row** listing all five paths — not five rows. - **The trigger**: each detected issue records the last user action before the crash — the click that set it off. Recurring errors get their stacks symbolicated from the **second occurrence**, matched against your repo to surface a suspected file and line. This needs your sourcemaps to be reachable — see [Source attribution](/docs/source-attribution). ## Promote, snooze, mute - **Promote** — one click creates a real ticket that flows through the entire pipeline: [AI triage](/docs/ai-triage), source attribution, tracker issue. Promoting the same candidate twice returns the same ticket. - **Snooze** — hides an error until it happens 10 more times. - **Mute** — silences it permanently. - Dismissed items clean themselves up after 30 days. ## Flood-proof by design An error storm can't take you down — or drown you: | Layer | Guard | | --- | --- | | Widget | Max 10 reports per minute, with client-side dedup | | Server | Dedups again on ingest | | Queue | Capped at 200 active items, with automatic pruning | ## Detected issues vs. reported bugs A reported bug starts from a person who clicked capture; a detected issue starts from a crash in a session where nobody did. Both end up as the same kind of ticket once promoted — full capture context, triage, tracker sync. The review queue is the only difference: machines propose, you decide. --- Source: https://rebase.dev/docs/integrations # Trackers & sync > How tickets become issues in GitHub, Linear, Jira and Asana — and how status flows back to Rebase. Tickets land in the tracker you already use — GitHub, Linear, Jira or Asana — as structured issues with the full context attached. No second inbox, no copy-paste. Slack gets the notifications. ## Connecting a tracker Every integration is connected from the widget: **Settings → Integrations**, pick the tracker, authorize, choose the destination. All four are first-class: | Tracker | Connection | Destination picker | | --- | --- | --- | | [GitHub](/docs/github) | GitHub App | Repository | | [Linear](/docs/linear) | OAuth | Team + intake state | | [Jira](/docs/jira) | OAuth (Jira Cloud) | Site + project + issue type | | [Asana](/docs/asana) | OAuth | Workspace + project | OAuth and App tokens are stored encrypted and refreshed before they expire. Disconnect any time — existing issue links are preserved. ## Auto-create and manual push New tickets can draft a tracker issue **immediately** — title, description, AI triage, screenshot — without anyone touching the tracker. It's a toggle per integration, and issue creation runs as a queued job that retries transient failures. Prefer to file by hand? Every ticket thread has a **push to tracker** control that creates the issue on demand in any connected tracker. ## What lands in the issue - **The screenshot, inside the issue itself** — uploaded natively on Linear, Jira and Asana, inlined on GitHub. Not a link back to another tool. - **The AI triage** — summary, severity, repro steps and type, formatted into the issue body so the assignee starts with context. - **Smart labels** — issues are labelled `rebase`, plus the AI's classification as your tracker's conventional label (bug, enhancement or question on GitHub). - **The suspected source location**, when available — see [Source attribution](/docs/source-attribution). ## Two-way status sync Close the issue in GitHub, Linear or Asana and the Rebase ticket resolves — its pin leaves the page. Reopen it and the ticket reopens. Each sync direction is toggleable. :::note Jira syncs by polling GitHub, Linear and Asana status flows inbound via signed webhooks. Jira status syncs via scheduled polling instead, so inbound changes land within the polling interval. ::: ## Field mapping Map Rebase fields like priority and status onto your tracker's own taxonomy — labels on GitHub, fields on Linear and Jira, workflow values on Jira. Field mapping is available on **GitHub, Linear and Jira**; Asana syncs status but has no field mapping. ## Duplicates, cross-referenced When a ticket is detected as a duplicate, the canonical tracker issue gets a "see also" cross-reference comment, so related reports are visible from the original issue. Duplicates are detected and linked — see [AI triage](/docs/ai-triage). ## Tracker badges in the widget Tickets show their tracker reference — `#142`, `ENG-142` — as a badge that jumps straight to the issue. Badges are visible to owners and team members only. ## Slack Slack is for notifications rather than issues: paste one incoming webhook and Rebase posts when tickets are filed and resolved. See [Slack notifications](/docs/slack). --- Source: https://rebase.dev/docs/github # GitHub > Install the GitHub App, pick a repo, and every ticket opens as a labelled issue with the screenshot inlined. Every Rebase ticket can open as a GitHub issue in the repo you choose — labelled, with the screenshot inlined and the AI triage in the body — and status syncs both ways. ## Connect 1. In the widget, open **Settings → Integrations → GitHub**. 2. Install the **GitHub App** — no personal access tokens to mint or rotate. 3. Pick the repository issues should file into. ## What a ticket becomes A structured GitHub issue, created the moment the ticket lands (or on demand from the ticket thread): - Title and description, with the **AI triage** — summary, severity, repro steps, type — formatted in the body. - The **screenshot inlined** in the issue itself. - Labels: `rebase`, plus the classification as GitHub's conventional label — `bug`, `enhancement` or `question`. - The **suspected source location** as a commit-pinned file and line reference when available — because Rebase can match captured context against your repo tree. See [Source attribution](/docs/source-attribution). - A link back to the full Rebase report. Auto-create is a per-integration toggle; creation runs as a queued job with retries. ## Status, both ways - Close the issue in GitHub → the Rebase ticket resolves and its pin leaves the page. - Reopen the issue → the ticket reopens. - Resolve in Rebase → the GitHub issue closes. Inbound sync arrives via signed webhooks, and each direction is toggleable. ## Field mapping Map Rebase priority and status onto your labels — your taxonomy, not ours. Configure it from the integration's settings in the widget. ## The badge Tickets linked to GitHub show their `#number` as a badge in the widget (owners and team only) — one click jumps to the issue. ## Bonus: better source attribution Connecting GitHub doesn't just receive issues — it makes tickets smarter. Captured paths, component names, test ids and button text are matched against your repo tree to produce commit-pinned permalinks in the suspected-source section. --- Source: https://rebase.dev/docs/linear # Linear > Tickets file into the team and intake state you choose, with the screenshot uploaded natively. Rebase files tickets into the Linear team and intake state you choose — screenshot uploaded natively, triage in the description, status synced both ways. ## Connect 1. In the widget, open **Settings → Integrations → Linear**. 2. Authorize via **OAuth**. 3. Pick the **team** and the **intake state** new issues should land in. Reports don't pile into a generic inbox — they enter your workflow already routed. ## What a ticket becomes A Linear issue in the team you chose: - The **screenshot uploaded natively** to the issue — not linked from elsewhere. - The **AI triage** — summary, severity, repro steps, type — in the description. - A `rebase` label plus the AI's classification. - A link-back attachment to the full Rebase report. - The suspected source location when available — see [Source attribution](/docs/source-attribution). Auto-create is a per-integration toggle; creation runs as a queued job with retries. You can also push any ticket manually from its thread. ## Status, both ways Your board is the truth: as the issue moves through your Linear workflow, the Rebase ticket follows. Close it in Linear and the ticket resolves — the pin leaves the page; reopen it and the ticket reopens. Inbound sync arrives via signed webhooks, and each direction is toggleable. ## Field mapping Map Rebase priority and status into Linear's fields and workflow values from the integration's settings. ## The badge Tickets linked to Linear show their identifier — `ENG-142` — as a badge in the widget (owners and team only) that jumps straight to the issue. --- Source: https://rebase.dev/docs/jira # Jira > Structured issues in the right Jira Cloud project — status syncs back via scheduled polling. Every ticket can become a structured Jira issue in the right project — screenshot attached natively, triage in the description, status kept in sync with your workflow. ## Connect 1. In the widget, open **Settings → Integrations → Jira**. 2. Authorize via **OAuth** (Jira Cloud). 3. Pick the **site**, **project** and **issue type** new issues should use. ## What a ticket becomes A proper Jira issue, formatted the way Jira expects: - The **screenshot attached natively** to the issue. - The **AI triage** — summary, severity, repro steps, type — in the description. - A `rebase` label plus the AI's classification. - A link back to the full Rebase report. - The suspected source location when available — see [Source attribution](/docs/source-attribution). Auto-create is a per-integration toggle; creation runs as a queued job with retries. You can also push any ticket manually from its thread. ## Status, both ways — via polling Resolve the issue in Jira and the Rebase ticket closes; resolve in Rebase and the Jira issue transitions. :::note How inbound sync arrives Jira status syncs via **scheduled polling** rather than webhooks, so inbound changes land within the polling interval — slightly behind real time, never out of sync. Each direction is toggleable. ::: ## Field mapping Map Rebase priority and status into Jira's fields and workflow values — your taxonomy, your workflow states. Configure it from the integration's settings in the widget. ## The badge Tickets linked to Jira show their key — `ACME-77` — as a badge in the widget (owners and team only) that jumps straight to the issue. --- Source: https://rebase.dev/docs/asana # Asana > Every ticket becomes a task in the workspace and project you pick, ready to schedule. Every ticket can become an Asana task in the workspace and project you choose — screenshot uploaded natively, triage in the description, completion synced both ways. ## Connect 1. In the widget, open **Settings → Integrations → Asana**. 2. Authorize via **OAuth**. 3. Pick the **workspace** and **project** new tasks should land in. ## What a ticket becomes An Asana task where your team already plans work — so bugs and change requests get scheduled like everything else, not lost in a side channel: - The **screenshot uploaded natively** to the task. - The **AI triage** — summary, severity, repro steps, type — in the description. - A `rebase` tag plus the AI's classification. - A link back to the full Rebase report. - The suspected source location when available — see [Source attribution](/docs/source-attribution). Auto-create is a per-integration toggle; creation runs as a queued job with retries. You can also push any ticket manually from its thread. ## Status, both ways Complete the task in Asana and the Rebase ticket resolves — its pin leaves the page. Un-complete it and the ticket reopens. Resolve in Rebase and the task completes. Inbound sync arrives via signed webhooks, and each direction is toggleable. :::note Asana syncs status both ways but does not support field mapping — that's a GitHub, Linear and Jira feature. ::: ## The badge Tickets linked to Asana show a badge in the widget (owners and team only) that jumps straight to the task. --- Source: https://rebase.dev/docs/slack # Slack notifications > Post new and resolved tickets to a channel with one incoming webhook — no OAuth, no bot install. Post ticket activity to a Slack channel with a single incoming webhook. No OAuth dance, no bot to install — paste one URL and toggle what you want to hear about. ## Connect 1. In Slack, create an **incoming webhook**: Apps → Incoming Webhooks → Add to Slack, and pick the channel. 2. In the widget, open **Settings → Integrations → Slack** and paste the webhook URL (it starts with `https://hooks.slack.com/`). 3. Hit **Test the connection** — Rebase posts a short message to your channel so you know it works before a real ticket does. :::warning Treat the webhook like a password Anyone holding the URL can post to your channel. Rebase stores it encrypted, never echoes it back — the UI only ever shows a masked hint of the connected webhook — and clears it from the form after saving. ::: ## What gets posted Two events, each with its own toggle (both on by default): | Event | Posted when | | --- | --- | | New ticket | A ticket is filed | | Resolved | A ticket is resolved | Messages are compact and link straight to the ticket: the headline and title, then a context line with the page's pathname — and, for new tickets, who reported it. ## Delivery Notifications are best-effort by design and never block the ticket pipeline: - Delivery runs as a queued job with retries and backoff for transient failures. - If Slack reports the webhook as revoked, Rebase stops retrying immediately. - If Slack is down, tickets still flow to Rebase and your tracker exactly as normal. ## Disconnect **Settings → Integrations → Slack → Disconnect** revokes the stored webhook. Your event preferences are kept, so reconnecting later is one paste away. --- Source: https://rebase.dev/docs/mcp # MCP for coding agents > Give Claude Code, Cursor or any MCP client the full captured context over five tools — locally, over stdio. `@rebasedotdev/mcp` plugs Rebase into Claude Code, Cursor, VS Code, Windsurf or any MCP-capable agent. The agent pulls the real captured context — console errors, failed requests, user steps, suspected source — instead of a one-line description, and its replies land in the same in-page thread your team is watching. The server runs **locally over stdio** on the developer's machine. It opens no network listener; the only network traffic is HTTPS to the Rebase API. Requires Node 18+. ## 1. Mint a token In the widget: **Settings → Project → API tokens**. Tokens are prefixed `rbk_`, shown **once**, stored only as a hash, and expire after 365 days by default. Each token carries explicit scopes: | Scope | Allows | | --- | --- | | `tickets:read` | List, search and read tickets | | `tickets:write` | Update ticket status | | `comments:write` | Post comments | :::tip Read-only agents are a first-class setup For observer agents, mint a token with only `tickets:read` — it can find and understand tickets but never change anything. Write scopes are opt-in. ::: ## 2. Connect your editor **Claude Code** — one command: ```bash title="Claude Code" claude mcp add rebase -e REBASE_API_TOKEN=rbk_your_token -- npx -y @rebasedotdev/mcp ``` **Cursor and VS Code** — the widget's MCP settings offer a one-click install link, or add the JSON yourself. **Windsurf, or any MCP client** — the same JSON config everywhere: ```json title=".mcp.json" { "mcpServers": { "rebase": { "command": "npx", "args": ["-y", "@rebasedotdev/mcp"], "env": { "REBASE_API_TOKEN": "rbk_your_token" } } } } ``` Environment variables: | Variable | Required | Default | Purpose | | --- | --- | --- | --- | | `REBASE_API_TOKEN` | yes | — | The project-scoped `rbk_` token. Treat it like a password — keep it in the client's `env` config, never in source control. | | `REBASE_API_URL` | no | `https://api.rebase.dev` | Override the API origin. | ## The five tools | Tool | What it does | | --- | --- | | `list_tickets` | List tickets, newest first — id, title, status, pathname, AI severity, duplicate links. | | `search_tickets` | Semantic search by meaning — "checkout is broken" finds the 500 on /orders. | | `get_ticket` | Everything captured for one ticket, optionally with the screenshot as an image. | | `add_comment` | Post to the ticket's thread — visible to the reporter and team in the widget. | | `update_ticket_status` | Move a ticket between open, in-progress and resolved. | ### list_tickets Parameters: `status` (optional: `open`, `in-progress`, `resolved`), `limit` (1–50, default 25), `cursor` (from a previous page's `nextCursor`). ### search_tickets Parameters: `q` (required, 2–500 characters, natural language), `status` (optional), `limit` (1–25, default 10). Returns scored results; costs **zero AI credits**, searches the last 90 days. Rate-limited — batch questions rather than looping. ### get_ticket Parameters: `ticket_id` (required), `include_screenshot` (optional boolean). Returns the full ticket — AI triage, pinned element, suspected source, console, network failures, session events, comments, tracker links. With `include_screenshot: true` the screenshot arrives as an image block (PNG, up to 10 MB; the fetch times out at 20 seconds and fails gracefully rather than hanging the agent). ### add_comment Parameters: `ticket_id`, `body` (1–5,000 characters, plain text). Posted as the person who minted the token; `@Full Name` mentions notify that member. ### update_ticket_status Parameters: `ticket_id`, `status` (`open`, `in-progress`, `resolved`). Resolving removes the ticket's pin from the page and notifies watchers — do it only once a fix has actually landed. ## A typical loop 1. `list_tickets` with `status: "open"` — find what needs attention. 2. `get_ticket` with `include_screenshot: true` — read the capture, look at the screenshot, start from the suspected file. 3. Fix the code with the agent's own tools — Rebase never touches your code. 4. `add_comment` — tell the reporter what changed. 5. `update_ticket_status` to `resolved` — the pin disappears for everyone. ## Limits and errors Per-token rate limits: **120 reads / 30 writes / 30 searches per minute**. Every API call has a 20-second timeout. | Error | Meaning | | --- | --- | | 401 | Token missing, mistyped, revoked or expired — deliberately indistinguishable. | | 402 | The project's subscription is inactive; writes pause until billing is restored. | | 403 | The token lacks the required scope — e.g. a read-only token trying to resolve. | | 404 | The ticket belongs to a different project than the token — one token, one project. | ## Security posture - Runs as a child process of your agent; stdio in, HTTPS out — nothing listens on the network. - No code execution, no file access, no secrets in logs; error messages carry only the HTTP status and the API's own text, never the token. - Rotate or revoke tokens any time from the widget — revocation takes effect immediately. --- Source: https://rebase.dev/docs/teams # Teams, roles & notifications > The four roles, one-click invites, @handles, unlimited users — and how email stays signal instead of noise. Enough team machinery to run real projects — none of the enterprise sludge. Four roles, one-click invites, unlimited users, and email that stays signal. ## The four roles There are exactly four roles — enforced in the UI **and** the API: | Capability | Owner | Team | Commenter | Viewer | | --- | --- | --- | --- | --- | | Read tickets and threads | yes | yes | yes | yes | | File tickets and comment | yes | yes | yes | — | | Resolve tickets | yes | yes | — | — | | See capture data (console, network, steps) | yes | yes | — | — | | Re-run AI triage | yes | yes | — | — | | Manage members, integrations, billing | yes | — | — | — | Roles are set per member at invite time and can be changed any time. Guardrail: you can't remove the last owner. ## Invites Invite by email from **Settings → Team**. The invite is a signed, expiring link — one click signs the person in and activates them, no code round-trip, nothing guessable. Invites are throttled per recipient against abuse. New teammates get a warm first run: a welcome card — complete your profile, see the team you're joining — before their first report. ## @handles Handles are optional, globally-unique public usernames: - Mention by handle, invite by handle. - Mentions are stored by handle, so renames never break them. - Once a member sets one, their **email disappears from the roster** — identity without exposing addresses. - Handles can be claimed cold from the marketing site by verifying your email, with live availability checks and suggestions as you type. ## Users Every plan includes unlimited users — no seats to buy, count or manage: - **Unlimited members at every role** — teammates, clients and stakeholders join free. - Pending invites are free too. - Removing a member takes effect immediately. See [Billing & trial](/docs/billing) for the full pricing picture. ## Notifications Two speeds, so email stays worth opening: - **Immediate** — @mentions and invites go out at once. - **Digested** — new tickets, comments and resolutions coalesce per ticket into a single "N new updates" email per 5-minute window. Every notification deep-links to the customer page with the right ticket open and pinned — not to a dashboard. And there's a real preference center: per-project, per-category controls (mentions, comments, ticket activity, product emails), plus one-click, no-login unsubscribe links in every email. ## Profiles Name, avatar (up to 2 MB, safely re-encoded on upload), job role — and email changes are verified by a one-time code. --- Source: https://rebase.dev/docs/billing # Billing & trial > One flat plan per website: what it costs, what's included, and what happens if a subscription lapses. One flat plan, priced per website. A website covers one verified site — the host you claimed and its www sibling count as a single unit. ## The price | | Monthly | Yearly | | --- | --- | --- | | Rebase Pro | $69/month | $690/year — about two months free | Everything is included in the one plan: - 200 AI triage credits per project, monthly - Semantic search — uncapped, never metered by credits - All four tracker integrations (GitHub, Linear, Jira, Asana) and Slack notifications - MCP server access for coding agents - Proactive error detection (detected issues) - 90-day screenshot retention - **Unlimited users** — invite your whole team and clients, at every role There is no per-seat pricing and nothing to manage — see [Teams, roles & notifications](/docs/teams). ## The trial 7 days, **card required**, once per user. Checkout runs through Stripe and returns you to your own site, with the widget picking setup back up where it left off. Returning owners are billed at checkout rather than starting a second trial. ## Self-serve billing - **Stripe Checkout** to start; the **customer portal** for card changes and invoices. - **Cancel at period end** from the widget, with optional feedback. - **Resume within the grace period** and nothing is interrupted. A just-paid project unlocks instantly — activation is driven by Stripe webhooks, not a timer. ## If a subscription lapses Lapse means **read-only, not deletion**: - The widget goes read-only; write APIs return `402`. - Your data and pins remain exactly where they were. - Reactivating restores everything instantly. :::note There is no free tier — the trial is the way in. Every role is included in the flat price: viewers and commenters don't cost extra. ::: --- Source: https://rebase.dev/docs/security # Security & privacy > Passwordless auth, short-lived sessions, widget isolation, tenant isolation — and where the paperwork lives. Private by default, boring on purpose. This page is the posture at a glance; the full detail lives in [What gets captured](/docs/what-gets-captured) and the legal pages linked at the bottom. ## Sign-in Passwordless by design — there are no passwords to phish and no password database to breach: - Sign-in is a **6-character one-time email code**: 15-minute life, 5 attempts, and aggressively rate-limited (3 codes per 5 minutes per email). - Invited teammates skip even that: the invite link is a signed, expiring credential that signs them straight in. ## Sessions - **Access tokens live 15 minutes, in memory.** Nothing rides on cookies, so classic CSRF doesn't apply. - **Refresh tokens rotate on every use** (30-day lifetime). Reusing a rotated token is treated as theft: the whole chain burns and every device is signed out. Tokens are bound to the browser and stored server-side only as hashes. - **Sign out everywhere else** revokes every other device's session with one click. - Malformed auth responses fail closed — the widget would rather not load than load wrong. ## The widget on your page - Renders in an **isolated shadow root** with its own styles; pointer-transparent except for its own UI. It can't restyle your page or intercept your events. - Never injects HTML from untrusted strings — no `innerHTML`, no `eval`; all text renders through escaping-by-construction, including AI output. - URLs are validated at every sink (avatars, issue links, navigation) against an http(s) allow-list. - Cookieless requests with short timeouts; every request carries a unique request id. - Degrades gracefully when storage is blocked (private mode) or the network fails. ## Your data - **Masked before memory**: everything typed is masked by default; passwords, card fields and one-time codes can never be captured. Response bodies are never captured; request bodies are opt-in. No session video, no DOM replay, no keystroke log. - **Scrubbed twice**: known secret shapes are swept in the browser before submission, and payloads are scrubbed again on ingest. - **Hard tenant isolation**: every token is scoped to one project; a cross-tenant ID simply doesn't exist — it's a 404. - **Encrypted in transit and at rest**, and never used to train models. - **Screenshots handled like evidence**: re-encoded server-side (strips anything that isn't pixels), served via 10-minute signed URLs, deleted after 90 days. ## Rate limiting Every endpoint class has purpose-built limits — sign-in codes, invites, uploads, API, webhooks — abuse-resistant by default. ## API access Programmatic access uses `rbk_` tokens: explicit scopes, shown once, stored as SHA-256 hashes, 365-day default expiry, last-used visibility, immediate revocation. Read-only tokens are a first-class setup for observer agents — see [MCP for coding agents](/docs/mcp). ## The paperwork All live, all public: - [Privacy policy](/privacy) - [Terms of service](/terms) - [Data Processing Addendum](/dpa) - [Subprocessor list](/subprocessors) - [Cookie policy](/cookie-policy) - [AI policy](/ai-policy) - [Compliance guide](/compliance-guide)