> ## Documentation Index
> Fetch the complete documentation index at: https://docs.fingerprint.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Google Chrome Extension

### Using Fingerprint in Google Chrome Extensions

A typical use-case represents getting a valid [`visitor_id`](/reference/js-agent-get-function#visitor_id) via your extension. After validating it with the [Server API](/reference/server-api) or [webhooks](/docs/webhooks), data provided by Fingerprint might be crucial for your internal decision making, user scoring, and protecting sensitive actions for your business.

There are two general strategies to integrate Fingerprint into an extension. You can get Fingerprint result by opening your website temporarily in a new window. Another way demonstrates injecting the [Fingerprint JavaScript agent](/reference/js-agent) into the website's iframe and performing fingerprinting there.

Both solutions are showcased in the [Chrome extension repository](https://github.com/fingerprintjs/fingerprintjs-pro-chrome-extension-example). The example extension is also available on the [Chrome Web Store](https://chrome.google.com/webstore/detail/fingerprintjs-example-bro/knppbjgkegnlbhddedbilnfmnkdocekn).

<Warning>
  The example extension is currently still implemented using JavaScript agent v3, see the [migration
  guide](/reference/migrating-from-v3-to-v4) for more information.
</Warning>

### New window strategy

With this approach, the Chrome extension creates a new window that points to an external website hosted by you. This website uses our Fingerprint agent to obtain the `result`. This data is then passed back to the extension using a [native communication channel](https://developer.chrome.com/docs/extensions/mv3/messaging/#external-webpage).

#### Sample use

1. Configure and serve a publicly available web page containing the Fingerprint JavaScript agent. It's recommended to use the [Custom subdomain setup](/docs/custom-subdomain-setup) or one of our cloud proxy integration to [protect the JavaScript agent from ad blockers](/docs/protecting-the-javascript-agent-from-adblockers) and increase accuracy. This website must be served over HTTPS.

```javascript JavaScript theme={"theme":"github-dark-dimmed"}
// Script on your website

// Your chrome extension id
const extensionId = 'CHROME_EXTENSION_ID';

// Initialize the agent
const fpPromise = import('https://fpjscdn.net/v4/PUBLIC_API_KEY').then((Fingerprint) =>
  Fingerprint.start({
    endpoints: 'https://metrics.yourwebsite.com/',
  }),
);

fpPromise
  .then((fp) => fp.get())
  .then((result) => {
    // Pass the result back to the chrome extension
    // Note: this API is only available in chromium based browsers and only on pages served via HTTPS
    chrome.runtime.sendMessage(extensionId, {
      type: 'fpjs-result',
      data: result,
    });
  });
```

2. In the extension's `manifest.json`, add the `externally_connectable` manifest property. Make sure you've specified the `service_worker` property in the `background` section as well.

```javascript JavaScript theme={"theme":"github-dark-dimmed"}
// manifest.json of your chrome extension
{
...
"externally_connectable": {
	// URL to the external site that uses our Agent
  "matches": ["https://your-website.com/*"]
},
...
"background": {
  // Name of your background script file
  "service_worker": "background.js"
},
...
}
```

3. Add the following code snippet into your background script. It will allow you to obtain results from Fingerprint inside your extension's codebase.

```javascript JavaScript theme={"theme":"github-dark-dimmed"}
let currentWindow;

async function closeCurrentWindow() {
  if (currentWindow?.id) {
    try {
      await chrome.windows.remove(currentWindow.id);
      currentWindow = undefined;
    } catch (error) {
      // Handle error
    }
  }
}

async function getFingerprint() {
  await closeCurrentWindow();

  currentWindow = await chrome.windows.create({
    url: 'WEBSITE_URL',
    type: 'popup',
    focused: false,
  });

  return new Promise((resolve) => {
    const handleExternalMsg = async (externalMessage) => {
      if (externalMessage?.type === 'fpjs-result' && externalMessage?.data?.visitor_id) {
        resolve(externalMessage.data);

        chrome.runtime.onMessageExternal.removeListener(handleExternalMsg);

        // Close created window after receving result
        await closeCurrentWindow();
      }
    };

    // Register listener for messages from our website
    chrome.runtime.onMessageExternal.addListener(handleExternalMsg);
  });
}

// Add a listener for messages from your extension requesting data from the JavaScript agent
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
  if (message.type === 'get-visitor-id') {
    getFingerprint().then(sendResponse);

    // Required for async operations, otherwise, chrome won't pass the result back to the sender
    return true;
  }
});
```

4. Receive and use the `result` data in your extension's logic.

```javascript JavaScript theme={"theme":"github-dark-dimmed"}
export function getFingerprintResult() {
  return new Promise((resolve, reject) => {
    chrome.runtime.sendMessage(
      {
        type: 'get-visitor-id',
      },
      (message) => {
        if (message?.visitor_id) {
          resolve(message);
        } else {
          reject(new Error('Failed to get visitor data'));
        }
      },
    );
  });
}

getFingerprintResult().then((result) => {
  // Use result
});
```

### Iframe strategy

With this strategy, the extension appends an iframe into the DOM with the URL of the external website and communicates with it using [Window.postMessage() API](https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage).

Alternatively, you can append the iframe into the DOM served on the extension page (e.g. in the popup). There are several benefits of not using a content script:

* Other extensions don't have access to the iframe content (e.g. adblockers).
* There are no required special permissions in the `manifest.json`.
* Several anti-fingerprinting techniques and tracking protections can't identify and block this approach.

#### Sample use

1. Configure and serve a publicly available web page containing the Fingerprint JavaScript agent. It's recommended to use the [Custom subdomain](/docs/custom-subdomain-setup). The website must be served over HTTPS.

```javascript theme={"theme":"github-dark-dimmed"}
// Script on your website

const parentOrigin = 'chrome-extension://CHROME_EXTENSION_ID';

// Check if we are in iframe
if (window.parent !== window) {
  // Initialize the agent
  const fpPromise = import('https://fpjscdn.net/v4/PUBLIC_API_KEY').then((Fingerprint) =>
    Fingerprint.start({
      endpoints: 'https://fp.yourdomain.com', // Subdomain setup URL
    }),
  );

  fpPromise
    .then((fp) => fp.get())
    .then((result) => {
      // Send the result to parent window
      window.parent.postMessage(
        {
          type: 'fpjs-result',
          data: result,
        },
        parentOrigin,
      );
    });
}
```

2. Add the following code to your extension where you need to get `result` data.

<Note>
  **DOM API and background scripts**

  With this approach, your extension needs access to the DOM API, therefore, according to the [Manifest v3 limitations](https://developer.chrome.com/docs/extensions/mv3/intro/), it's not possible to use the following snippet in the background script.
</Note>

```javascript JavaScript theme={"theme":"github-dark-dimmed"}
export function getFingerprintResult(container) {
  const iframeUrl = new URL('https://yourwebsite.com');
  const iframe = document.createElement('iframe');

  // Apply styles to the iframe
  iframe.style.width = '100%';
  iframe.style.height = '200px';
  iframe.style.border = 'none';

  iframe.src = iframeUrl.href;

  return new Promise((resolve) => {
    const handler = (event) => {
      if (event.origin !== iframeUrl.origin || event.source !== iframe.contentWindow) {
        return;
      }

      const eventData = event.data;

      if (eventData?.type === 'fpjs-result' && eventData?.data?.visitor_id) {
        window.removeEventListener('message', handler);
        iframe.remove();
        resolve(eventData.data.visitor_id);
      }
    };

    // Listen for messages from iframe
    window.addEventListener('message', handler);
    container.appendChild(iframe);
  });
}

const container = document.querySelector('.main');

getFingerprintResult(container).then((result) => {
  // Use result
});
```

### Documentation

You can find the full documentation in the official [GitHub repository](https://github.com/fingerprintjs/fingerprintjs-pro-chrome-extension-example).
