Chrome extension
Add Rybbit analytics to your Chrome extension
Manifest V3 requires every piece of executable code to ship inside the extension package, and the extension_pages Content Security Policy is fixed at script-src 'self' 'wasm-unsafe-eval'; object-src 'self' with no way to relax it. A remote <script> tag can therefore never load in an extension page. Bundle the @rybbit/js SDK into your popup, options or side panel page instead, and grant host_permissions for the analytics host.
Get your tracking snippet
In your Rybbit dashboard, open Site Settings → Tracking Script and copy your snippet. It looks like this:
<script src="https://app.rybbit.io/api/script.js?siteId=YOUR_SITE_ID" defer></script>YOUR_SITE_ID is the numeric ID of your site. If you self-host Rybbit, app.rybbit.io is the domain of your own instance.
You only need the site ID from the snippet; the script tag itself is not used in an extension.
Add the snippet to Chrome extension
- Install the SDK in the extension project:
npm install @rybbit/js- Initialise it in the entry script of each extension page you want to track (the popup from
action.default_popup, the options page fromoptions_ui.page, the side panel fromside_panel.default_path). The SDK needswindowanddocument, so do not import it in the service worker.
import rybbit from "@rybbit/js";
await rybbit.init({
analyticsHost: "https://app.rybbit.io/api",
siteId: "YOUR_SITE_ID",
});
// Extension pages have URLs like chrome-extension://<id>/popup.html.
// Report a readable path instead:
rybbit.pageview("/popup");- Grant the extension permission to call the analytics host. Requests from extension pages to origins listed in
host_permissionsare not subject to CORS:
{
"manifest_version": 3,
"host_permissions": ["https://app.rybbit.io/*"]
}- Build the extension with your bundler (Vite, webpack, Rollup) so
@rybbit/jsends up inside the package, then reload the unpacked extension atchrome://extensions.
The default extension CSP does not restrict connect-src, so no content_security_policy entry is required. If you define your own policy, add https://app.rybbit.io to its connect-src.
Do not initialise the SDK in a content script. Content scripts run inside third-party websites; tracking there records other people's pages under your site ID, and content scripts are subject to the host page's same-origin policy in any case.
Verify installation
Open your live site in a new tab and click through a few pages. Within a few seconds the pageviews appear in the Rybbit dashboard.
If nothing shows up:
- View the page source and search for
script.js?siteId=to confirm the snippet is on the page. - Open the browser Network tab and check that
script.jsreturns200and thatPOSTrequests go to/api/track. - Disable ad blockers, or set up a proxy so the script loads from your own domain.
- See the script troubleshooting guide for other common causes.
Track custom events
Call rybbit.event() from the page script, or use data attributes on buttons in your popup HTML:
document.getElementById("save")?.addEventListener("click", () => {
rybbit.event("settings_saved", { theme: "dark" });
});<button data-rybbit-event="upgrade_click" data-rybbit-prop-plan="pro">Upgrade</button>Troubleshooting
Refused to load the scriptin the popup console: the fixedextension_pagesCSP blocked a remote tag. Remove it and use the SDK.POST /api/trackblocked by CORS:host_permissionsis missing or does not match. The pattern must include the path wildcard:https://app.rybbit.io/*.- Self-hosted Rybbit: replace
https://app.rybbit.ioin bothanalyticsHostandhost_permissionswith your own instance URL. - Every pageview shows the extension ID as hostname: expected. Extension pages live on
chrome-extension://<id>; userybbit.pageview("/name")for readable paths.
Next steps
- Track custom events such as signups, purchases and button clicks.
- Identify users to connect sessions to accounts.
- Proxy the script through your own domain to bypass ad blockers.
- Script attributes let you skip or mask URLs and tag events.