Google Chrome Extension
Using Fingerprint in Google Chrome Extensions
A typical use-case represents getting a valid visitorId
among other result data via your extension. After validating it with the Server API or 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 FingerprintJS JavaScript agent into the website's iframe and performing fingerprinting there.
Both solutions are showcased in the Chrome extension repository. The example extension is also available on the Chrome Web Store.
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.
Sample use
- Configure and serve a publicly available web page containing the Fingerprint JavaScript agent. It's recommended to use the Custom subdomain setup or one of our cloud proxy integration to protect the JavaScript agent from ad blockers and increase accuracy. This website must be served over HTTPS.
// Script on your website
// Your chrome extension id
const extensionId = "your-chrome-extension-id";
// Initialize the agent
const fpPromise = import('https://fpjscdn.net/v3/your-public-api-key')
.then(FingerprintJS => FingerprintJS.load({
endpoint: ["metrics.yourwebsite.com", FingerprintJS.defaultEndpoint]
}));
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,
});
});
- In the extension's
manifest.json
, add theexternally_connectable
manifest property. Make sure you've specified theservice_worker
property in thebackground
section as well.
// 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"
},
...
}
- Add the following code snippet into your background script. It will allow you to obtain results from Fingerprint inside your extension's codebase.
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: 'your_website_url',
type: 'popup',
focused: false,
});
return new Promise(resolve => {
const handleExternalMsg = async (externalMessage) => {
if (externalMessage?.type === 'fpjs-result' && externalMessage?.data?.visitorId) {
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;
}
},
);
- Receive and use the
result
data in your extension's logic.
export function getFingerprintJsResult() {
return new Promise((resolve, reject) => {
chrome.runtime.sendMessage(
{
type: 'get-visitor-id',
},
message => {
if (message?.visitorId) {
resolve(message);
} else {
reject(new Error('Failed to get visitor data'));
}
},
);
});
}
getFingerprintJsResult().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.
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
- Configure and serve a publicly available web page containing the Fingerprint JavaScript agent. It's recommended to use the Custom subdomain. The website must be served over HTTPS.
// Script on your website
// Check if we are in iframe
if (window.parent !== window) {
// Initialize the agent
const fpPromise = import('https://fpjscdn.net/v3/your-public-api-key')
.then(FingerprintJS => FingerprintJS.load({
endpoint: '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,
}, '*');
});
}
- Add the following code to your extension where you need to get
result
data.
DOM API and background scripts
With this approach, your extension needs access to the DOM API, therefore, according to the Manifest v3 limitations, it's not possible to use the following snippet in the background script.
export function getFingerprintJsResult(container) {
const iframe = document.createElement('iframe');
// Apply styles to the iframe
iframe.style.width = '100%';
iframe.style.height = '200px';
iframe.style.border = 'none';
iframe.src = 'your_website_url';
return new Promise(resolve => {
const handler = (event) => {
const eventData = event.data;
if (eventData?.type === 'fpjs-result' && eventData?.data?.visitorId) {
window.removeEventListener('message', handler);
iframe.remove();
resolve(eventData.data.visitorId);
}
};
// Listen for messages from iframe
window.addEventListener('message', handler);
container.appendChild(iframe);
});
}
const container = document.querySelector('.main');
getFingerprintJsResult(container).then(result => {
// Use result
});
Documentation
You can find the full documentation in the official GitHub repository.
Updated 4 months ago