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 your site's ID, a 12-character string such as a1b2c3d4e5f6. Older sites may use a numeric ID, which still works. 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",
});init() records a pageview for the page by itself (unless Initial Page View is turned off for the site), so don't call rybbit.pageview() as well or each open counts twice. Extension pages have URLs like chrome-extension://<id>/popup.html, so the popup shows up as /popup.html.
- 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>; the path (/popup.html,/options.html) still tells pages apart. For custom paths, turn off Initial Page View under Site Settings → Tracking and callrybbit.pageview("/name")afterinit()in each page you track. The setting applies to every page using this site ID, not only the popup.
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.