`.
**What gets blurred:** only the elements you want
**Applies to:** Jams requested via Intercom or Recording Link
By default, Jam recognizes the same privacy selectors used by FullStory, Hotjar, LogRocket, Sentry, and others. If you're already using these tools, your existing privacy setup works automatically with Jam.
## Setup
Blurred content is only supported on sites with verified Jam.js installations. Follow the Recording Links setup guide before proceeding.
Blurring is enabled by default once the snippet is installed.
### Quickstart
#### Want to blur something?
Use data attributes:
```html theme={"theme":"css-variables"}
{ccNumber}
```
Or meta tag:
```html theme={"theme":"css-variables"}
```
Or SDK:
```javascript theme={"theme":"css-variables"}
jam.initialize({ blurSelectors: ".secret-stuff" });
```
#### Want to unblur something?
```html theme={"theme":"css-variables"}
{ccNumber}
```
### What gets blurred automatically
#### Standard selectors
* **Jam:** `[data-jam-blur]`
* **rrweb:** `.rr-block`, `.rr-mask`, `.rr-ignore`
* **Standard HTML autocomplete attributes:** `cc-number`, `cc-exp`, `cc-csc`, `tel`, `email`
* **Common name/id patterns** for SSN, bank accounts, credit cards, photo IDs, driver's license
#### Session replay tools
* **FullStory:** `.fs-exclude`, `.fs-mask`, `.fs-block`, `.fs-unmask` (unblur)
* **Hotjar:** `[data-hj-suppress]`, `[data-hj-masked]`
* **LogRocket:** `[data-private]`
* **Microsoft Clarity:** `[data-clarity-mask]`, `[data-clarity-unmask]` (unblur)
* **Sentry:** `.sentry-block`, `.sentry-mask`, `[data-sentry-block]`, `[data-sentry-mask]`
* **OpenReplay:** `[data-openreplay-obscured]`, `[data-openreplay-hidden]`
* **Highlight.io:** `.highlight-block`, `.highlight-mask`, `.highlight-ignore`
* **ContentSquare:** `[data-cs-mask]`, `[data-cs-encrypt]`, `[data-cs-capture]` (unblur)
* **Matomo:** `[data-matomo-mask]`
#### Analytics tools
* **Heap:** `[data-heap-redact-text]`, `[data-heap-redact-attributes]`, `[data-heap-ignore]`, `.heap-ignore`
* **Amplitude:** `[data-amp-mask]`, `[data-amp-unmask]` (unblur)
### Add custom selectors
#### Using SDK
```javascript theme={"theme":"css-variables"}
import * as jam from "@jam.dev/recording-links/sdk";
jam.initialize({ blurSelectors: ".my-custom-blur-class" });
// or array
jam.initialize({ blurSelectors: [".blur-class-1", ".blur-class-2"] });
// or function
jam.initialize({ blurSelectors: () => `.my-${Math.ceil(Math.random() * 100)}-blur-class` });
```
#### Using script tag with meta tags
```html theme={"theme":"css-variables"}
```
### Opt out of blurring for specific elements
Use `[data-jam-blur="no"]`:
```html theme={"theme":"css-variables"}
Blurred in rrweb, but not in Jam
```
### Test before you ship
Create a Recording Link using your verified recording URL.
Click your own link and start recording.
Navigate to pages that should be blurred and confirm the behavior.
### Limitations
* Content in iframes cannot be selectively blurred
* Flashes of unblurred content may occur during captured pageloads
* When browser window is resized during recording, blurred content may briefly become visible
# Auto-deploy
Source: https://jam.dev/docs/auto-deploy
Install Jam on every browser in your organization automatically using Google Admin Console. No manual setup.
Enterprise admins give every member instant Jam access through the Google Admin Console.
## How to set up Jam in Google Admin Console
**Prerequisite:** Make sure you have Google Workspace Admin Access.
Navigate to [admin.google.com](https://admin.google.com) and log in with admin credentials.
Go to **Devices → Chrome → Apps & extensions → Users & Browsers**.
Click **+ Add → Add from Chrome Web Store**.
Search for **jam.dev** and select it.
Set the policy to **Force Install** or **Force install + pin to browser toolbar**.
Click **Save** to apply settings.
Jam installs automatically the next time employees open Chrome.
# Azure DevOps
Source: https://jam.dev/docs/azure-devops
Turn every Jam into an Azure DevOps work item with full technical context. Set project, type, and priority from inside the extension.
Connect Jam to Azure DevOps to turn every bug capture into a work item with full debug context already attached. Engineers get everything they need to reproduce the issue without any manual information gathering.
You need the Jam Chrome extension installed. See [Getting Started](/docs/introduction) if you haven't set it up.
## Prerequisites
Before connecting Jam to Azure DevOps, enable third-party OAuth access in your Azure DevOps organization:
1. Go to your Azure DevOps organization settings.
2. Under **Policies**, enable **Third-party application access via OAuth**.
## What's included in every Azure DevOps work item
Every Azure DevOps issue created from Jam automatically includes:
* Console logs
* Fully inspectable network requests
* URL, timestamp, and country
* Device, OS, and browser
* Viewport size
* Network speed
Use the Jam browser extension to capture your bug.
In the Jam extension, click **Link you can share** and change the destination to Azure DevOps.
Complete the Azure DevOps OAuth flow to connect your account.
Once connected, set up your work item from Jam: choose the project, team, priority, assignees, and more.
Click **Create issue**. Jam creates the Azure DevOps work item and opens it in a new tab.
Click **Edit fields** during work item setup to manage which Azure DevOps fields appear in the Jam extension. Remove fields you don't use to keep the process fast.
Create an Azure DevOps work item from any Jam you've already captured in two clicks.
You must be logged into Jam to use this feature. Logged-out users will not see the **Send to App** option.
Open the Jam you want to convert into an Azure DevOps work item.
Click **Send to App** and select Azure DevOps.
If this is your first time using Jam + Azure DevOps, you'll be redirected to authenticate.
Enter the project, team, priority, and any other fields you need.
Click **Create issue** to send the Jam to Azure DevOps.
# Browser support
Source: https://jam.dev/docs/browser-support
See which Chromium browsers Jam supports and which features work in each.
Jam is supported on all Chromium browsers: Chrome, Edge, Arc, Brave, Opera. More browser support is coming soon. Jam supports both logged in and incognito browser sessions.
## Supported browsers
| Browser | Console logs | Network requests | WebSockets |
| ------- | ------------ | ---------------- | ------------- |
| Chrome | ✅ | ✅ | ✅ |
| Edge | ✅ | ✅ | ✅ |
| Arc | ✅ | ✅ | ✅ |
| Brave | ✅ | ✅ | Not supported |
| Opera | ✅ | ✅ | ✅ |
Firefox and Safari are not currently supported.
Install the Jam extension from the [Chrome Web Store](https://chrome.google.com/webstore/detail/jam/iohjgamcilhbgmhbnllfolmkmmekfmci). The same extension works across all supported Chromium browsers.
For detailed incognito setup, see [Incognito Sessions](/docs/extension-setup#incognito-sessions).
# CLI
Source: https://jam.dev/docs/cli
Authenticate, read Jam data, and create Jams from your terminal. Built for shell scripts, CI jobs, and AI coding agents.
The Jam CLI runs every Jam read and write from your terminal. Authenticate once, then pipe Jam data into shell scripts, CI jobs, or AI coding agents.
The CLI runs on macOS, Linux, and Windows (x64 and arm64). Windows publishes an x64 binary; Windows on ARM runs it under the built-in x64 emulation. You can also run the CLI under Windows Subsystem for Linux (WSL) — on WSL, authenticate with a personal access token (see [Authenticate](#authenticate)).
## Install
Run the installer:
```bash theme={"theme":"css-variables"}
curl -fsSL https://native.jam.dev/install | bash
```
The script detects your OS and architecture, downloads the matching binary into `~/.local/bin/jam`, and adds that directory to your shell `PATH`. Open a new shell or `source` your rc file, then confirm the install:
```bash theme={"theme":"css-variables"}
jam --version
```
Open PowerShell and run:
```powershell theme={"theme":"css-variables"}
powershell -c "irm https://native.jam.dev/install.ps1 | iex"
```
The script downloads the binary into `%LOCALAPPDATA%\Programs\Jam`, points a `jam` command at it, and adds it to your user `PATH`. Open a new terminal, then confirm the install:
```powershell theme={"theme":"css-variables"}
jam --version
```
Only an x64 binary is published. Windows on ARM runs it under the built-in x64 emulation — the same one-liner works, with no extra steps.
**Locked-down PowerShell.** If your environment blocks `irm | iex` (a restricted execution policy is common on managed machines), install by hand: download the binary from [`https://native.jam.dev/download/windows/x64`](https://native.jam.dev/download/windows/x64), save it as `jam.exe` in a folder such as `%LOCALAPPDATA%\Programs\Jam\bin`, then add that folder to your `PATH` under **Settings → Edit environment variables for your account**. Open a new terminal and run `jam --version`.
### Creating video Jams needs ffmpeg
`jam create jam` extracts the poster image and probes the audio track with `ffmpeg`/`ffprobe` when you create a **video** Jam. Every other command works without it. Install ffmpeg if you plan to create video Jams from the CLI:
```bash macOS theme={"theme":"css-variables"}
brew install ffmpeg
```
```bash Linux theme={"theme":"css-variables"}
sudo apt install ffmpeg
```
```powershell Windows theme={"theme":"css-variables"}
winget install ffmpeg
```
Or skip ffmpeg entirely by passing `posterImagePath` and `screenDimensions` explicitly on the create payload.
## Authenticate
Every read and write command needs an authenticated session. The CLI supports two modes.
On WSL, use a personal access token. The browser login flow expects your browser and the CLI to share the same local address, which WSL splits between Windows and Linux, so token auth is the reliable path for now.
Run:
```bash theme={"theme":"css-variables"}
jam auth login
```
The CLI opens an OAuth flow in your default browser, exchanges the authorization code for access and refresh tokens, and stores them in `~/.config/jam/credentials.json`.
Use a personal access token for headless environments, CI jobs, or WSL:
```bash theme={"theme":"css-variables"}
echo "jam_pat_abc123..." | jam auth login --token
```
Create PATs in [**Settings → MCP**](https://jam.dev/s/settings/mcp). See [Personal Access Tokens](/docs/personal-access-tokens) for scopes, expiration, and rotation guidance.
### Check auth status
```bash theme={"theme":"css-variables"}
jam auth status
```
Prints the authenticated user, workspace, and auth method. Pass `--json` to consume the same data from a script.
### Log out
```bash theme={"theme":"css-variables"}
jam auth logout
```
Revokes tokens server-side where supported and clears the local credential store.
### Where credentials live
The CLI stores credentials at `~/.config/jam/credentials.json` with `0600` permissions, the same model used by `gh`, `aws`, `gcloud`, and other major developer CLIs.
Bypass the credential file entirely by setting `JAM_TOKEN` in your shell. The CLI uses the env-var token for the lifetime of the process and never writes it to disk.
## First steps
After install and auth, run this short loop to confirm the CLI talks to your workspace:
```bash theme={"theme":"css-variables"}
jam auth status
jam list jams --limit 5
jam get jam
```
`auth status` confirms the CLI can read the stored token. `list jams` returns a page of Jams from your workspace. `get jam` walks a single Jam by ID. From there, scan the [command reference](#command-reference) for the command you need.
## Command reference
Every command supports `--help`. The machine-readable surface (argument types, flags, output shapes) lives at `jam agent-context`.
| Command | Summary | Output |
| ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------- | ----------- |
| `jam auth login [--token]` | Authenticate via browser OAuth or stdin PAT | Side effect |
| `jam auth logout` | Revoke tokens and clear credentials | Side effect |
| `jam auth status` | Show current user, workspace, and auth method | Single |
| `jam get jam ` | Fetch a Jam by ID | Single |
| `jam get metadata ` | Structured `jam.metadata()` events | Paginated |
| `jam get console [--level ]` | Console log events | Paginated |
| `jam get network [--status ] [--method ] [--host ] [--content-type ]` | Network requests | Paginated |
| `jam get events ` | Full unfiltered event stream | Paginated |
| `jam get transcript ` | WebVTT transcript for video Jams | Single |
| `jam get intents ` | Cached intents summary | Single |
| `jam get screenshots --out ` | Download image media into a directory | Receipt |
| `jam get frames [--at ] [--from --to --count ] [--size ] [--out ]` | Save still video frames as jpgs | Receipt |
| `jam list jams [...]` | List Jams in the workspace | Paginated |
| `jam list folders [...]` | List folders | Paginated |
| `jam list members [...]` | List workspace members | Paginated |
| `jam create jam ''` | Create a screenshot or video Jam | Receipt |
| `jam create comment [--at ]` | Add a comment to a Jam | Receipt |
| `jam create folder ` | Create a folder | Receipt |
| `jam create reaction ` | React to a comment | Receipt |
| `jam update jam [--title ] [--description ] [--folder ]` | Rename a Jam, rewrite its description, or move it to a folder | Receipt |
| `jam update folder --name ` | Rename a folder | Receipt |
| `jam update comment ` | Rewrite a comment you authored | Receipt |
| `jam delete jam [-y]` | Archive a Jam | Receipt |
| `jam delete comment [-y]` | Delete a comment you wrote | Receipt |
| `jam delete folder [-y]` | Delete a folder and archive the Jams in it | Receipt |
| `jam delete reaction ` | Take back your reaction on a comment | Receipt |
| `jam recording-links urls` | List connected recording domains | Paginated |
| `jam recording-links list [--limit ] [--after ]` | List the team's recording links | Paginated |
| `jam recording-links get ` | Fetch a recording link by public ID | Single |
| `jam recording-links jams [--limit ] [--after ]` | List Jams recorded through a link | Paginated |
| `jam recording-links create --name [--recording-url-id ] [--folder ] [--jam-title ] [--reference ] [--expires-at ] [--metadata ]` | Create a reusable recording link | Receipt |
| `jam recording-links update [--name ] [--folder ] [--reference ] [--jam-title ] [--expires-at ] [--metadata ]` | Edit a recording link's settings | Receipt |
| `jam recording-links revoke ` | Revoke a recording link | Receipt |
| `jam recording-links verify [--wait]` | Verify a connected recording domain | Receipt |
| `jam skills list` | List bundled agent skills | List |
| `jam skills install [name] [--target ] [--project]` | Install bundled skill into an agent's directory | Receipt |
| `jam skills path [--target ] [--project]` | Show where skills would be installed | Single |
| `jam skills source` | Print the absolute path to the bundled `SKILL.md` | Path |
| `jam agent-context` | Print the machine-readable command surface as JSON | Single |
| `jam doctor` | Show CLI channel, URLs, version, and auth status | Single |
| `jam upgrade [--target ]` | Install the latest or pinned CLI binary | Side effect |
| `jam uninstall [-y]` | Remove the CLI and local data | Side effect |
### Read Jam data
Three commands return different views of the same Jam:
* `jam get jam ` returns the top-level record (title, author, URL, dates, folder, and kind-specific data).
* `jam get metadata ` returns structured metadata events emitted by the page via the `jam.metadata()` SDK call.
* `jam get intents ` returns the structured summary (what the user was trying to do, observed issues, impact). It returns `{ "status": "not_requested", "value": null }` when no summary is available. Treat that as absence, not an error.
Three commands return slices of the captured event stream:
* `jam get console [--level error|warn|info|debug|log]`
* `jam get network [--status 5xx|] [--method GET|POST|...] [--host ] [--content-type ]`
* `jam get events ` returns the unfiltered event stream.
All three accept `--limit` (default 50, max 500) and `--after ` for pagination.
Two media reads:
* `jam get transcript ` returns `{ status, vtt }`. `vtt` is null while generation is pending.
* `jam get screenshots --out ` downloads the Jam's images into ``. For screenshot Jams that's the primary and secondary screenshots, for video and replay Jams it's the poster image.
### Video frames
`jam get frames ` saves still frames from a video Jam as jpgs, so you or an agent can see what was on screen instead of only reading the transcript. Frames land in `--out` (default `./jam-frames//`) and the command prints the saved paths as JSON.
```bash theme={"theme":"css-variables"}
# overview grid: no flags, one labeled image spanning the whole video
jam get frames
# a single moment, or several explicit timestamps
jam get frames --at 7000
jam get frames --at 4000,7000,9000
# evenly-spaced frames across a window
jam get frames --from 2000 --to 10000 --count 5
```
The mode depends on the flags:
* **Overview grid.** No flags. Saves one grid image with frames evenly spaced across the whole video, each cell labeled with its timestamp. The frame count scales with duration (6 for short clips up to 16 for long ones). Best for orienting before you know which moment you care about.
* **Timestamps.** `--at `, single or comma-separated. Saves one jpg per timestamp.
* **Window.** `--from --to --count `. Saves N evenly-spaced frames across the range.
`--size` accepts `small`, `medium`, or `large` (default `medium`) and sets the frame height. When frames aren't available (a screenshot Jam, or a video not hosted on Cloudflare Stream), the command prints the reason to stderr and exits non-zero.
### List workspace collections
```bash theme={"theme":"css-variables"}
jam list jams --query "checkout" --type video --limit 20
jam list folders --order-by createdAt
jam list members --query "@example.com"
```
`--type` accepts `screenshot`, `video`, `replay`, or `unknown`. `--order-by` accepts `createdAt` or `updatedAt`. `--limit` defaults to 20 (max 500). All three list commands accept `--after ` for pagination. See `jam list jams --help` for all filters.
### Create and update Jams
Create a screenshot Jam from a JSON payload:
```bash theme={"theme":"css-variables"}
jam create jam '{
"url": "https://example.com/checkout",
"title": "Checkout button is broken",
"screenshotPath": "./checkout.png",
"screenDimensions": { "width": 1440, "height": 900 }
}'
```
The payload requires `url`, `screenDimensions`, and exactly one screenshot source (`screenshotPath`, `screenshotDataUrl`, or `screenshotMediaId`). To create a video Jam, set `kind` to `"video"` and provide `videoPath`. The poster image is generated downstream if you omit `posterImagePath`.
To avoid escaping a large JSON blob on the command line, read the payload from a file with an `@` prefix, or pipe it in on stdin:
```bash theme={"theme":"css-variables"}
jam create jam @jam.json # read from a file
cat jam.json | jam create jam # pipe via stdin
```
Run `jam create jam --help` for both payload shapes, or `jam agent-context` for the full machine-readable JSON Schema (under `create.jam`, on the `source` arg).
Add a comment to a Jam:
```bash theme={"theme":"css-variables"}
jam create comment "Logs at 00:42 show a 500 on /checkout." --at 42000
```
`` is Markdown. `--at` pins the comment to a video timestamp in milliseconds.
Rewrite a comment you left earlier:
```bash theme={"theme":"css-variables"}
jam update comment "Logs at 00:42 show a 500 on /checkout — fixed in #1423."
```
The new body replaces the old one entirely, and you can only edit comments you authored. `` is the `id` the create call returned; the share URL it printed works too.
React to a comment, or take the reaction back:
```bash theme={"theme":"css-variables"}
jam create reaction "👀"
jam delete reaction "👀"
```
Reactions are one of 🐛 💜 ✅ 👀 ❓ 👏 🔥 👍 — the same set the share page offers. Both commands are idempotent, and removing only clears your own reaction.
Rename a Jam, rewrite its description, or move it to a folder:
```bash theme={"theme":"css-variables"}
jam update jam --title "Checkout fails on Safari"
jam update jam --description "Repro steps are in the console log."
jam update jam --folder
jam update jam --folder ""
```
Pass at least one flag. Only the fields you pass change. Pass an empty string to `--folder` to remove the Jam from its current folder. `--description` takes Markdown, and an `@mention` of a teammate's email notifies them. Editing the title or description needs an Admin or Creator role; moving folders does not.
### Create and rename folders
```bash theme={"theme":"css-variables"}
jam create folder "Checkout bugs"
jam update folder checkout-bugs --name "Checkout"
```
`create folder` returns `{ id, shortId, name }`, so you can file a Jam into the new folder straight away with `jam update jam --folder `. Folder names are not unique — run `jam list folders` first if you mean to reuse an existing folder rather than add another one with the same name.
`update folder` accepts a folder name, its short ID, or its UUID. Renaming leaves the folder's Jams and short ID untouched.
### Delete Jams, comments, and folders
```bash theme={"theme":"css-variables"}
jam delete jam
jam delete comment
jam delete folder
```
Archiving a Jam takes it out of your lists and search but keeps the recording, so you can restore it from the dashboard. Deleting a folder archives every Jam inside it and reports how many in `archivedJamCount`. Deleting a comment is permanent and takes its attachments with it — only the comment's author can do it.
Each command asks you to confirm first. Pass `-y` (or `--yes`) to skip the prompt. Scripts and agents have no terminal to answer on, so they must pass `-y`; without it the command refuses rather than assuming an answer.
### Recording links
A recording link is a shareable URL that collects Jams: anyone who opens it can record and submit a Jam back to your workspace. A link captures console and network logs only when it records from a connected recording domain (a "recording URL"), so list your connected domains first and pass one when you create the link. See [Recording Links](/docs/recording-links) for the dashboard workflow.
```bash theme={"theme":"css-variables"}
jam recording-links urls
jam recording-links create --name "Support intake" --recording-url-id --folder "Bug reports"
```
`create` returns the link's public ID and shareable URL. Every other command addresses the link by that public ID.
```bash theme={"theme":"css-variables"}
jam recording-links jams --limit 50
jam recording-links update --name "Q3 support intake"
jam recording-links revoke
```
`jams` lists the Jams recorded through a link. `update` edits its settings (name, folder, reference, Jam title, expiration, metadata). `revoke` soft-deletes the link so it stops accepting new recordings, while the Jams it already collected stay. To connect a new domain, run `jam recording-links verify ` and open the returned link in a browser where Jam is live on that domain.
## Output mode
The CLI pretty-prints when stdout is a TTY and emits compact JSON when output is piped. Force JSON output in any context with the top-level `--json` flag:
```bash theme={"theme":"css-variables"}
jam --json auth status
jam --json get jam | jq '.title'
```
Machine consumers (agents, scripts) should pass `--json` so output stays parseable regardless of where the command runs.
## Pagination
Paginated commands return:
```json theme={"theme":"css-variables"}
{
"items": [...],
"next_cursor": "" | null,
"truncated": true | false,
"hint": "Use --after= to fetch the next page."
}
```
Walk every page in a shell loop:
```bash theme={"theme":"css-variables"}
cursor=""
while :; do
page=$(jam --json get console "$ID" --limit 500 ${cursor:+--after "$cursor"})
echo "$page" | jq -c '.items[]'
cursor=$(echo "$page" | jq -r '.next_cursor // empty')
[ -z "$cursor" ] && break
done
```
`--limit` caps each page at 500. Defaults: 50 for `get` commands, 20 for `list` commands.
## Exit codes
The exit code is authoritative. Branch on it, not on stderr parsing.
| Code | Name | When |
| ---- | ---------- | ------------------------------------------------------ |
| 0 | success | Command completed. |
| 1 | generic | Unclassified error. |
| 2 | usage | Invalid flag or argument. |
| 3 | auth | Not authenticated or token rejected (HTTP 401 or 403). |
| 4 | not\_found | Resource missing (HTTP 404). |
| 5 | validation | Enum or integer validation failed. |
| 6 | server | Upstream returned 5xx. |
In JSON mode, errors print to stderr as `{"error":{"code":"...","message":"..."}}`. `valid_values` is included on validation errors when applicable.
## Environment variables
| Variable | Purpose |
| ------------------ | ---------------------------------------------------------------------------------------------------------------------------------- |
| `JAM_TOKEN` | Bearer token used in place of stored credentials. The CLI uses it for the lifetime of the process and never writes it to disk. |
| `JAM_NO_TELEMETRY` | Set to `1` to disable all CLI telemetry: lifecycle events (install, update, uninstall) plus per-command usage and error reporting. |
## Update and uninstall
Install the latest CLI binary:
```bash theme={"theme":"css-variables"}
jam upgrade
```
Install a specific version:
```bash theme={"theme":"css-variables"}
jam upgrade --target 0.2.0
```
The CLI verifies the new binary's checksum, runs a `--version` smoke test, and replaces the running binary atomically. On Windows the running `.exe` is locked, so each version installs into its own folder and `jam upgrade` re-points a `jam` command at the new one — a `jam` process you already have open keeps running the old version until you restart it.
Remove the CLI and local data:
```bash theme={"theme":"css-variables"}
jam uninstall
```
Skip the confirmation in non-interactive environments:
```bash theme={"theme":"css-variables"}
jam uninstall --yes
```
Uninstall removes `~/.local/bin/jam`, the `~/.local/state/jam/` state directory, your stored credentials in `~/.config/jam/`, and the `PATH` marker the installer added to your shell rc files. On Windows it removes the `%LOCALAPPDATA%\Programs\Jam` install folder and drops its entry from your user `PATH`.
`jam uninstall` is irreversible. Re-install via the curl one-liner to recover.
## Use the CLI with AI coding agents
The CLI ships two surfaces for AI coding agents: a bundled skill and a JSON command catalog.
### Bundled skills
`jam skills install` writes the bundled `SKILL.md` into the location your agent runtime expects (Claude Code, Cursor, Codex, OpenCode). The CLI auto-detects the runtime via environment variables, then falls back to project-level marker directories before defaulting to Claude.
```bash theme={"theme":"css-variables"}
jam skills install # auto-detect target, user-global install
jam skills install --project # install into the current repo
jam skills install --target cursor # explicit target
jam skills path # preview destination without writing
jam skills list # list bundled skills
```
The skill teaches your agent which command to reach for at each step (read Jam, filter errors, leave a comment) and how to interpret the structured output.
### Machine-readable command surface
`jam agent-context` prints the command surface as JSON: argument types, flag enums, default limits, and output shapes. Pair it with `--json` on every read or write call to keep tool wrappers thin.
```bash theme={"theme":"css-variables"}
jam agent-context | jq '.commands["get.jam"]'
```
The shape is locked by a snapshot test, so the JSON stays stable across releases inside the same `schema_version`.
# ClickUp
Source: https://jam.dev/docs/clickup
Turn every Jam into a ClickUp task with full technical context. Set workspace, folder, and list fields from inside the extension.
Connect Jam to ClickUp to turn every bug capture into a ClickUp task in seconds. All the technical context engineers need is attached automatically so you can skip the manual debug-info gathering.
You need the Jam Chrome extension installed. See [Getting Started](/docs/introduction) if you haven't set it up.
## What's included in every ClickUp task
Every ClickUp task created from Jam automatically includes:
* Console logs
* Fully inspectable network requests
* URL, timestamp, and country
* Device, OS, and browser
* Viewport size
* Network speed
Use the Jam browser extension to capture your bug.
In the Jam extension, click **Link you can share** and change the destination to ClickUp.
Complete the ClickUp OAuth flow to connect your account.
Once connected, set up your task from Jam: choose the workspace, folder, list, assignee, and more.
Click **Create task**. Jam creates the ClickUp task and opens it in a new tab.
ClickUp workspace guests can also create Jams. Their Space field defaults to the shared space they have access to, while they can continue filling out other public fields.
Click **Edit fields** during task setup to manage which ClickUp fields appear in the Jam extension. Remove fields you don't use to keep the workflow fast.
Create a ClickUp task from any Jam you've already captured in two clicks.
You must be logged into Jam to use this feature. Logged-out users will not see the **Send to App** option.
Open the Jam you want to convert into a ClickUp task.
Click **Send to App** and select ClickUp.
If this is your first time using Jam + ClickUp, you'll be redirected to authenticate.
Enter the workspace, folder, list, assignee, and any other fields you need.
Click **Create task** to send the Jam to ClickUp.
A Jam account or workspace connects to multiple ClickUp workspaces.
Go to [**Settings → Integrations**](https://jam.dev/s/settings/integrations).
The ClickUp authentication flow opens in a new tab.
Select or deselect the ClickUp workspaces you want to connect to. Selected workspaces show a blue circle indicator.
Click **Connect Workspaces**.
After connecting, you'll see which ClickUp workspaces are linked to that Jam workspace.
Make sure to connect all the workspaces you need during this step. You won't be able to see the workspace selection screen again unless you disconnect and reconnect your ClickUp connection. Due to a ClickUp API limitation, ClickUp can only be connected to one Jam account or workspace at a time.
# Company overview
Source: https://jam.dev/docs/company-overview
Read Jam's company story, mission, values, AI policy, and security commitments.
Jam company pages explain who we are, what we build toward, how we use AI, and how we protect customer data.
## About Jam
Learn when Jam was founded, who uses Jam, and how to contact the team.
Read why Jam exists and what we believe bug reporting should become.
See how Jam builds with customers, ships fast, and keeps software simple.
## Review policies
See what data Jam AI uses and how third-party model providers handle it.
Review Jam's data protection practices, infrastructure, and compliance details.
# Configuration
Source: https://jam.dev/docs/configuration-overview
Configure the Jam SDK, Recording Links, browser access, and debugging defaults for the way your workspace captures bugs.
Jam configuration pages help you tune how Jam runs in your product, browser, and workspace rollout.
## Set up the Jam SDK
Attach app state, user IDs, and feature flags to every Jam.
Connect your own domain so Recording Links capture console logs and network requests.
Hide sensitive content automatically during Recording Link sessions.
## Tune browser and rollout settings
Limit the Chrome extension to the sites where you want Jam to run.
Install the Chrome extension across your organization with Google Admin Console.
Annotate local JPG, PDF, and HTML files opened in your browser.
Capture prompt, model, and app-state context when debugging AI apps.
# Creating a Jam
Source: https://jam.dev/docs/creating-a-jam
Install the Chrome extension or iOS app and share your first bug report in seconds. Every report includes console logs, network requests, and device info.
Jam captures bugs with full technical context (console logs, network requests, user events, and device metadata) automatically attached to every capture. You can capture from your browser with the Chrome extension, from your phone with the iOS app, or collect recordings from someone else with a Recording Link.
## From your browser
Visit the [Chrome Web Store](https://chromewebstore.google.com/detail/jam/iohjgamcilhbgmhbnllfolmkmmekfmci) and add the Jam extension to your browser.
Pin Jam to your browser toolbar so it's always one click away during testing and debugging.
Click the Jam icon, enter your email, and set up your account.
Click the Jam icon in your toolbar and select how you want to capture:
Captures the current page state with full technical context: console logs, network requests, user events, and device metadata.
Records your screen while you reproduce the issue step-by-step. Includes the same full technical context as a screenshot.
Automatically captures up to the last 2 minutes of activity. No need to reproduce the bug. Hit the Jam button after it happens.
Add a description, then click **Create**. Your Jam opens in a new tab with all technical details included, and the link is automatically copied to your clipboard.
Paste the Jam link into Slack, a Jira ticket, a GitHub issue, or wherever your team tracks bugs. You can also send it directly to an integration from the Jam share page.
Use keyboard shortcuts to capture even faster. Open the extension popup or trigger Instant Replay without leaving the page you're debugging. See [keyboard shortcuts](/docs/keyboard-shortcuts) for the full list.
## From your phone
Jam is currently available for iOS only.
[Download](https://apps.apple.com/de/app/jam-fix-bugs-faster/id6469037234?l=en-GB) Jam from the App Store.
Tap the Jam button and begin a screen broadcast to start capturing.
Navigate to your app or website and demonstrate the bug.
Stop the broadcast, trim your video, add a description, and send to your issue tracker
## From someone else
To collect a recording from a customer or teammate, create a [Recording Link](/docs/recording-links) and send it to them. They record in their browser with no install or account required, and the recorded Jam appears in your workspace.
# Custom logs
Source: https://jam.dev/docs/custom-logs
Attach live debug data like user IDs, app state, and feature flags to every Jam automatically with `jam.metadata()`.
A single `jam.metadata()` call ensures every Jam submitted from your website includes the metadata you need to debug. Custom logs work on all types of Jams, including requested Jams from Recording Links, Jam for Customer Support, and the Jam browser extension.
You can log anything: static values like `userId` and `teamId`, or live data from Redux and React state. Add what you need to debug, and it appears in every Jam.
## Installation
Install the Jam SDK into your project:
```bash theme={"theme":"css-variables"}
npm install '@jam.dev/sdk'
```
```bash theme={"theme":"css-variables"}
yarn add '@jam.dev/sdk'
```
## Usage
Call `jam.metadata()` once at the root of your app, in the same place you initialize your stores and render your root element. The callback you pass is invoked each time a Jam is captured, so the data is always live and never stale.
```javascript theme={"theme":"css-variables"}
import { jam } from "@jam.dev/sdk";
jam.metadata(() => {
return {
userId: 5492,
workspaceId: 'd3b59ce8-95f1-410c-bb5e-9dc598599336',
timeSincePageLoad: performance.now(),
// and any other debug data you'd need
};
});
```
Once configured, your metadata appears inside every Jam filed from your site.
## What data you can include
Beyond static values and local variables, you can pass in:
* **App store state**: user ID, workspace ID, the last 5 items in a checkout cart, which feature flags are enabled, and so on.
* **localStorage values**: any values stored locally in the browser.
* **Any serializable data**: whatever you need to reproduce or understand the bug.
## When is metadata captured?
Metadata is captured at the moment the bug reporter creates a Jam. Because the function you pass to `jam.metadata()` is called at capture time, the data reflects the live state of your app, not a stale snapshot from when the page loaded.
## Limits and constraints
When calling `jam.metadata()`, the returned object must meet all of the following requirements:
1. **Must be an `Object` instance**: for example, `{ a: 1, b: 2 }`. Passing `window` (a `Window` instance) will not work.
2. **Under 10 KB** when serialized.
3. **Serializable**: if `JSON.stringify` cannot stringify it, Jam cannot store it.
## Error handling
If your app throws an error, or any of the above constraints are not met, Jam will:
* Log the error in your browser's live console.
* Display an error message when the Jam is captured.
If `jam.metadata()` throws or returns an invalid value, the Jam is still created, but without your custom metadata. Check your browser console if you expect metadata and don't see it in a Jam.
# Connect your domain
Source: https://jam.dev/docs/custom-recording-domain
Connect your own domain to Recording Links so console logs and network requests get captured from every customer recording.
Connecting your domain ties your website or web app to Jam so Recording Links capture console logs, network requests, and user interactions alongside the screen recording. Without a connected domain, screen recordings still work, but developer logs aren't included.
A connected domain lets Jam:
* Serve Recording Links from your own domain, so links look branded and familiar to your customers.
* Capture console logs and network requests on every recording.
* Attach developer logs directly to Jams.
* Auto-blur sensitive fields like passwords and payment details while recording.
You need write access to your site to complete the steps below.
Every snippet on this page has a runnable example in the [recording-links-demos](https://github.com/jamdotdev/recording-links-demos) repo, including HTML, Next.js, Angular, and Google Tag Manager.
## Setup
Open [**Settings → Jam SDK**](https://jam.dev/s/settings/sdk) and pick your framework. The snippet there has your Team ID filled in, and the picker keeps your selection in the address bar (for example, `?framework=angular`), so you can share a link that opens on the right snippet.
Next to each snippet, click **Copy agent prompt** to get an install instruction with your Team ID and snippet filled in. Paste it into an AI coding agent like Claude Code or Cursor, and the agent installs the scripts for you.
Jam's Recorder and Capture scripts must be served from the **same origin** as your site so recordings and logs are correctly associated. Find your Team ID in [**Settings → Jam SDK**](https://jam.dev/s/settings/sdk), then install the snippet for your framework on all pages, or at minimum on the URL that hosts your recording route.
Paste this into the `` of every page.
```html theme={"theme":"css-variables"}
```
Use `next/script` with `strategy="beforeInteractive"`. Place the snippet in the **root** layout, not a nested route layout, since `beforeInteractive` is only honored from the root.
```tsx app/layout.tsx (App Router) theme={"theme":"css-variables"}
import Script from "next/script";
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
{children}
);
}
```
```tsx pages/_document.tsx (Pages Router) theme={"theme":"css-variables"}
import { Html, Head, Main, NextScript } from "next/document";
import Script from "next/script";
export default function Document() {
return (
);
}
```
Install the package, then initialize it once from your root component. Wrap the call in `ngZone.runOutsideAngular` so the SDK's listeners don't trigger change detection.
```bash theme={"theme":"css-variables"}
npm install @jam.dev/recording-links
```
```ts theme={"theme":"css-variables"}
import { Component, OnInit, NgZone } from '@angular/core';
import * as jam from '@jam.dev/recording-links/sdk';
@Component({ selector: 'app-root', template: '' })
export class AppComponent implements OnInit {
constructor(private ngZone: NgZone) {}
ngOnInit() {
this.ngZone.runOutsideAngular(() => {
jam.initialize({ teamId: 'your-team-id' });
});
}
}
```
With the SDK, the recorder loads lazily. The recorder and capture scripts download only when someone opens a page through a Recording Link, so `window.jam` won't exist on a normal page view.
Create a **Custom HTML** tag that fires on **All Pages**, and paste this in. It loads the same Recorder and Capture scripts as the other methods, with a guard so it runs once per page.
```html theme={"theme":"css-variables"}
```
GTM compiles Custom HTML tags as ES5, so it rejects `async`/`await` and dynamic `import()` with errors like *"async function requires ECMASCRIPT\_2017."* This snippet stays ES5 and injects the scripts as DOM elements, which avoids those errors.
**What each script does:**
* **`recorder.js`** shows the recording interface when a Recording Link is opened, and lets users record directly from your site.
* **`capture.js`** captures console logs, network requests, and click and key interactions while a recording is in progress.
To serve one page to more than one workspace, add a `jam:team` meta tag per workspace.
Wait for both scripts to load successfully on your target URL before verifying your domain. Check that your Content Security Policy isn't blocking them.
**Performance note:** Jam caches assets aggressively to reduce load. For the plain HTML snippet, place the `