### Install @innerworks-me/iw-auth-sdk Source: https://docs.innerworks.me/docs/getting-started/quickstart Install the @innerworks-me/iw-auth-sdk npm package. Node.js version 14 or higher is recommended. ```bash npm install @innerworks-me/iw-auth-sdk ``` -------------------------------- ### CSP header examples for SDK CDN Source: https://docs.innerworks.me/docs/getting-started/quickstart Example CSP headers that allow the Innerworks SDK dynamic loading. The first uses the script-src directive; the second uses default-src with a specific script-src override. Both whitelist the SDK CDN domain. ```http Content-Security-Policy: script-src 'self' https://sdk-cdn.prod.innerworks.me; ``` ```http Content-Security-Policy: default-src 'self'; script-src 'self' https://sdk-cdn.prod.innerworks.me; ``` -------------------------------- ### Initialise InnerworksMetrics with appId (React and Angular) Source: https://docs.innerworks.me/docs/getting-started/quickstart Initialise the InnerworksMetrics class with your project ID. The React example uses useState and useEffect; the Angular example uses ngAfterViewInit. Both are required to set up the SDK. ```typescript const [innerworksMetrics, setInnerworksMetrics] = useState(); useEffect(() => { setInnerworksMetrics( new InnerworksMetrics({ appId: 'your-project-id' }) ); }, []); ``` ```typescript innerworksMetrics: InnerworksMetrics | null = null; ngAfterViewInit(): void { this.innerworksMetrics = new InnerworksMetrics({ appId: 'your-project-id', }); } ``` -------------------------------- ### Time Range Query: curl GET with start_time Source: https://docs.innerworks.me/docs/advanced/batched-inference-results Retrieves results starting from a specific Unix timestamp (in milliseconds) using the start_time parameter. Here it requests 500 results starting from 1704067200000. ```bash curl --request GET \ --url 'https://api.prod.innerworks.me/api/v1/innerworks/inference/batch?start_time=1704067200000&batch_size=500' \ --header 'x-api-key: YOUR_API_KEY' ``` -------------------------------- ### Batched inference response JSON Source: https://docs.innerworks.me/docs/advanced/batched-inference-results Example response from the batched inference endpoint. Shows the top-level fields batchSize, results, and checkpoint, plus the fingerprinting and geolocation sub-objects when available. ```json { "batchSize": 1000, "results": [ { "requestId": "550e8400-e29b-41d4-a716-446655440000", "projectId": "project-123", "timestamp": "2024-01-01T10:00:00.000Z", "result": { "fingerprinting": { "browser": "Chrome", "fingerprint": "abc123def456", "deviceOs": "Windows", "socialId": "user-789" }, "geolocation": { "vpnDetectionReasons": "IP analysis", "vpnIsEnabled": true, "trueGeoLocationName": "United States", "trueGeoLocationCode": "US", "vpnProvider": "NordVPN", "vpnLocationCode": "CA", "stateUS": "NY", "trueUserIpAddress": "192.168.1.1", "requestIpAddress": "10.0.0.1" } } } ], "checkpoint": "eyJ2ZXJzaW9uIjoxLCJzdGF0ZSI6WzE3MDQxMDMyMDAwMDAsInJlcS0xMDAiXX0=" } ``` -------------------------------- ### Basic Request: curl GET /api/v1/innerworks/inference/batch Source: https://docs.innerworks.me/docs/advanced/batched-inference-results Retrieves the first batch of results with the default batch size of 1000. Replace YOUR_API_KEY with your actual API key. ```bash curl --request GET \ --url 'https://api.prod.innerworks.me/api/v1/innerworks/inference/batch' \ --header 'x-api-key: YOUR_API_KEY' ``` -------------------------------- ### Pagination with Checkpoint: curl GET with checkpoint Source: https://docs.innerworks.me/docs/advanced/batched-inference-results Uses the checkpoint from a previous response to retrieve the next batch of results. Replace CHECKPOINT_STRING with the actual base64-encoded checkpoint value. ```bash curl --request GET \ --url 'https://api.prod.innerworks.me/api/v1/innerworks/inference/batch?checkpoint=CHECKPOINT_STRING&batch_size=1000' \ --header 'x-api-key: YOUR_API_KEY' ``` -------------------------------- ### Invalid start time error response Source: https://docs.innerworks.me/docs/advanced/batched-inference-results Error response when the start_time query parameter is not before the current time. The cause field identifies the invalid parameter. ```json { "cause": "start_time", "error": "start_time must be before the current time" } ``` -------------------------------- ### Pagination workflow with checkpoint for batch inference Source: https://docs.innerworks.me/docs/advanced/batched-inference-results Shows the pagination workflow for the batch inference endpoint: an initial GET request with batch_size=1000, the checkpoint value returned in the response, and a second request that passes that checkpoint to fetch the next page. Repeat until the results array is empty. ```bash # First request curl --request GET \ --url 'https://api.prod.innerworks.me/api/v1/innerworks/inference/batch?batch_size=1000' \ --header 'x-api-key: YOUR_API_KEY' # Response contains checkpoint: "eyJ2ZXJzaW9uIjoxLCJzdGF0ZSI6WzE3MDQxMDMyMDAwMDAsInJlcS0xMDAiXX0=" # Second request using checkpoint curl --request GET \ --url 'https://api.prod.innerworks.me/api/v1/innerworks/inference/batch?checkpoint=eyJ2ZXJzaW9uIjoxLCJzdGF0ZSI6WzE3MDQxMDMyMDAwMDAsInJlcS0xMDAiXX0%3D&batch_size=1000' \ --header 'x-api-key: YOUR_API_KEY' ``` -------------------------------- ### GET /api/v1/innerworks/inference/batch Source: https://docs.innerworks.me/docs/advanced/batched-inference-results Retrieves multiple detection results in a single API call. Supports pagination via checkpoints and configurable batch sizes. ```APIDOC ## GET /api/v1/innerworks/inference/batch ### Description Retrieves multiple detection results (fingerprinting and geolocation data) for a specific project within a given time range. Supports pagination via checkpoints and batch sizes up to 5,000 records per request. ### Method GET ### Endpoint /api/v1/innerworks/inference/batch ### Parameters #### Header Parameters - **x-api-key** (string) - Required - Your API key for authentication. #### Query Parameters - **batch_size** (integer) - Optional - Number of results to return per request. Defaults to 1000. Maximum value is 5000. - **start_time** (integer) - Optional - Unix timestamp (in milliseconds) to start retrieving results from. If not provided, retrieves from the beginning of available data. - **checkpoint** (string) - Optional - Base64-encoded checkpoint string from a previous request. Used for pagination to retrieve the next batch of results. ### Request Example ``` curl --request GET \ --url 'https://api.prod.innerworks.me/api/v1/innerworks/inference/batch' \ --header 'x-api-key: YOUR_API_KEY' ``` ### Response #### Success Response (200) Returns a batch of inference results. The response includes a checkpoint string for pagination when more results are available. #### Response Example (Not provided in source documentation.) ``` -------------------------------- ### GET /api/v1/innerworks/inference/batch Source: https://docs.innerworks.me/docs/advanced/batched-inference-results Retrieves a batch of inference results with pagination support using a checkpoint token. The endpoint accepts batch_size, start_time, and checkpoint query parameters, and returns a checkpoint for subsequent requests. ```APIDOC ## GET /api/v1/innerworks/inference/batch ### Description Retrieves a batch of inference results. Supports pagination using a checkpoint token to retrieve all results for a time range. ### Method GET ### Endpoint `https://api.prod.innerworks.me/api/v1/innerworks/inference/batch` ### Parameters #### Query Parameters - **batch_size** (integer) - Required - The number of results to return per request. Must be between 1 and 5000. - **start_time** (string) - Optional - The start time for the query. Must be before the current time. - **checkpoint** (string) - Optional - A token used to continue pagination from a previous response. Obtained from the `checkpoint` field in the response. ### Request Example ``` curl --request GET \ --url 'https://api.prod.innerworks.me/api/v1/innerworks/inference/batch?batch_size=1000' \ --header 'x-api-key: YOUR_API_KEY' ``` ### Response #### Success Response (200) - **checkpoint** (string) - A token to use in the next request for pagination. - **results** (array) - The batch of inference results. Empty when no more data is available. #### Response Example ``` { "checkpoint": "eyJ2ZXJzaW9uIjoxLCJzdGF0ZSI6WzE3MDQxMDMyMDAwMDAsInJlcS0xMDAiXX0=", "results": [] } ``` ### Error Responses #### Invalid Batch Size ``` { "cause": "batch_size", "error": "batch_size must be between 1 and 5000" } ``` #### Invalid Start Time ``` { "cause": "start_time", "error": "start_time must be before the current time" } ``` #### Invalid Checkpoint ``` { "cause": "checkpoint", "error": "invalid checkpoint string" } ``` #### Missing API Key ``` { "statusCode": 401, "message": "Header x-api-key is required" } ``` ``` -------------------------------- ### Custom Batch Size: curl GET with batch_size=2000 Source: https://docs.innerworks.me/docs/advanced/batched-inference-results Retrieves a specific number of results by setting the batch_size query parameter to 2000. The maximum allowed batch size is 5000. ```bash curl --request GET \ --url 'https://api.prod.innerworks.me/api/v1/innerworks/inference/batch?batch_size=2000' \ --header 'x-api-key: YOUR_API_KEY' ``` -------------------------------- ### Get client IP from X-Forwarded-For header (Node.js) Source: https://docs.innerworks.me/docs/advanced/ip-check Use this when behind a reverse proxy, load balancer, CDN, or API gateway. It reads the X-Forwarded-For header, takes the first IP, and falls back to req.socket.remoteAddress if the header is missing. ```javascript const clientIP = req.headers['x-forwarded-for']?.split(',')[0]?.trim() || req.socket.remoteAddress; ``` -------------------------------- ### Get fingerprint request ID Source: https://docs.innerworks.me/docs/advanced/iframe-integration Extends iframeCallback to retrieve the requestId from the response and log it as the fingerprint request ID. ```javascript function iframeCallback(response) { //... rest of code // Get request ID for fingerprint const requestId = response.requestId; console.log('Fingerprint request ID:', requestId); } ``` -------------------------------- ### GET /api/v1/innerworks/inference Source: https://docs.innerworks.me/docs/advanced/api-access Retrieves detection results (fingerprinting and VPN status) for a given request ID. The response format can be 'simple' (default) or 'detailed'. ```APIDOC ## GET /api/v1/innerworks/inference ### Description Retrieves detection results (fingerprinting and VPN status) for a given request ID. The response format can be 'simple' (default) or 'detailed'. ### Method GET ### Endpoint https://api.prod.innerworks.me/api/v1/innerworks/inference?request_id={REQUEST_ID}&format={FORMAT} ### Parameters #### Query Parameters - **request_id** (string) - Required - The request ID obtained from the frontend SDK payload response. - **format** (string) - Optional - Response format: 'simple' (default) or 'detailed'. ### Headers - **x-api-key** (string) - Required - Your API key. ### Request Example curl --request GET \ --url https://api.prod.innerworks.me/api/v1/innerworks/inference?request_id={REQUEST_ID}&format={FORMAT} \ --header "x-api-key: {API_KEY}" ### Response #### Success Response (200) The response contains a `fingerprinting` object and a `geolocation` object. The fields depend on the `format` parameter. #### Simple Response - Fingerprinting - **fingerprinting.fingerprint** (string) - The fingerprint value. #### Simple Response - VPN Detection - **geolocation.vpnIsEnabled** (boolean) - Indicates whether the request was made by a user utilising a VPN. - **geolocation.trueGeoLocationName** (string) - The true location of the requesting user. - **geolocation.trueGeoLocationCode** (string) - The geolocation code of the user. #### Detailed Response - Fingerprinting - **fingerprinting.fingerprint** (string) - The fingerprint value. - **fingerprinting.browser** (string) - The user's browser. - **fingerprinting.deviceOs** (string) - The user's device OS. - **fingerprinting.socialId** (string) - The social ID provided via innerworksMetrics.send(). #### Detailed Response - VPN Detection - **geolocation.vpnIsEnabled** (boolean) - Indicates whether the request was made by a user utilising a VPN. - **geolocation.vpnDetectionReasons** (string) - The reason for VPN detection, if any. - **geolocation.trueGeoLocationName** (string) - The true location of the requesting user. - **geolocation.trueGeoLocationCode** (string) - The geolocation code of the user. - **geolocation.vpnProvider** (string) - The VPN provider, if applicable. - **geolocation.vpnLocationCode** (string) - The VPN location code, if applicable. - **geolocation.stateUS** (string) - The US state, if applicable. - **geolocation.trueUserIpAddress** (string) - The true user IP address. - **geolocation.requestIpAddress** (string) - The request IP address. #### Response Example (Simple) { "fingerprinting": { "fingerprint": "...." }, "geolocation": { "vpnIsEnabled": false, "trueGeoLocationName": "United Kingdom", "trueGeoLocationCode": "GB" } } #### Response Example (Detailed) { "fingerprinting": { "fingerprint": "....", "browser": "....", "deviceOs": "....", "socialId": "USER_ID" }, "geolocation": { "vpnIsEnabled": false, "vpnDetectionReasons": "None", "trueGeoLocationName": "United Kingdom", "trueGeoLocationCode": "GB", "vpnProvider": "...", "vpnLocationCode": "...", "stateUS": "...", "trueUserIpAddress": "...", "requestIpAddress": "..." } } ``` -------------------------------- ### Get client IP from direct TCP connection (Node.js) Source: https://docs.innerworks.me/docs/advanced/ip-check Use req.socket.remoteAddress when clients connect directly to your backend server. This provides the IP address from the TCP connection information. ```javascript const clientIP = req.socket.remoteAddress; ``` -------------------------------- ### Fetch inference result with curl Source: https://docs.innerworks.me/whats-new/2025/03/20/fetch-results-from-your-own-backend Makes a GET request to the Innerworks API using a request ID from the SDK and your API key. The default response includes fingerprint, VPN usage, and true location; add format=detailed for more data. ```bash curl --request GET \ --url 'https://api.prod.innerworks.me/api/v1/innerworks/inference?request_id={REQUEST_ID}' \ --header 'x-api-key: {API_KEY}' ``` -------------------------------- ### Batched Inference Endpoint: GET /api/v1/innerworks/inference/batch Source: https://docs.innerworks.me/docs/advanced/batched-inference-results Shows the HTTP method and path for the batched inference results endpoint. Use this endpoint to retrieve detection results in batches of up to 5,000 records per request. ```http GET /api/v1/innerworks/inference/batch ``` -------------------------------- ### Send fingerprinting request and get requestId Source: https://docs.innerworks.me/docs/getting-started/quickstart Send a fingerprinting request and capture the request ID from the response. The request ID is used to retrieve the fingerprint via a backend request. The fingerprint is not provided as a JWT in the frontend for security reasons. ```typescript if (innerworksMetrics) { const response: InnerworksResponse = await innerworksMetrics.send('my-user-id'); if (response.result === 'success') { // Fingerprinting Result - the request id is used to make a backend request const request_id = response.requestId; }; }; ``` -------------------------------- ### Query Detection Results via cURL Source: https://docs.innerworks.me/docs/advanced/api-access Use this cURL request to fetch detection results. Replace {REQUEST_ID}, {FORMAT}, and {API_KEY} with your specific values. ```bash curl --request GET \ --url https://api.prod.innerworks.me/api/v1/innerworks/inference?request_id={REQUEST_ID}&format={FORMAT} \ --header "x-api-key: {API_KEY}" ``` -------------------------------- ### JavaScript wrapper for refreshing InnerworksMetrics Source: https://docs.innerworks.me/docs/advanced/refreshing-the-sdk JavaScript wrapper that initializes InnerworksMetrics and provides a refresh function. Call refreshInnerworksMetrics() to reinitialize the SDK. ```JavaScript import { InnerworksMetrics } from '@innerworks-me/iw-auth-sdk'; let innerworksMetrics = null; function refreshInnerworksMetrics() { innerworksMetrics = new InnerworksMetrics({ appId: 'your-project-id' }); } refreshInnerworksMetrics(); ``` -------------------------------- ### Import InnerworksMetrics and InnerworksResponse Source: https://docs.innerworks.me/docs/getting-started/quickstart Import the InnerworksMetrics and InnerworksResponse types from the SDK on the page where you want to send metrics. ```typescript import { InnerworksMetrics, InnerworksResponse } from "@innerworks-me/iw-auth-sdk"; ``` -------------------------------- ### Embed hosted Innerworks SDK iframe Source: https://docs.innerworks.me/whats-new/2025/01/19/integrate-without-npm Place this iframe in your page to load the hosted SDK. Set projectId in the src query string. The iframe is hidden with display:none and communicates results via postMessage. ```html ``` -------------------------------- ### Simple VPN Detection Response Source: https://docs.innerworks.me/docs/advanced/api-access The simple VPN response includes vpnIsEnabled, trueGeoLocationName, and trueGeoLocationCode. ```json { "geolocation": { "vpnIsEnabled": false, "trueGeoLocationName": "United Kingdom", "trueGeoLocationCode": "GB" } } ``` -------------------------------- ### Detailed Fingerprinting Response Source: https://docs.innerworks.me/docs/advanced/api-access The detailed response includes browser, deviceOs, socialId, and fingerprint. ```json { "fingerprinting" : { "fingerprint": "....", "browser": "....", "deviceOs": "....", "socialId": "USER_ID" // this is the same id sent with innerworksMetrics.send() } } ``` -------------------------------- ### Add socialID to iframe src Source: https://docs.innerworks.me/docs/advanced/iframe-integration Shows how to set the iframe src with a socialID once the user ID is available. The iframe is initially empty and configured via JavaScript. Replace 'project_id' and 'social_id' with actual values. ```html // Configure iframe when user ID is available const iframe = document.getElementById("innerworks_sdk"); if (iframe instanceof HTMLIFrameElement) { iframe.src = "https://sdk.prod.innerworks.me?projectId=project_id&social_id=social_id"; } ``` -------------------------------- ### Missing API key error response Source: https://docs.innerworks.me/docs/advanced/batched-inference-results Error response when the required x-api-key header is missing. Returns HTTP status code 401. ```json { "statusCode": 401, "message": "Header x-api-key is required" } ``` -------------------------------- ### Verify JWT with jose and innerworks JWKS endpoint Source: https://docs.innerworks.me/docs/advanced/jwt-verification Use this async function to fetch the innerworks JWKS from https://api.prod.innerworks.me/api/v1/.well-known/jwks.json, verify the bearer token with compactVerify, and decode the payload. The jose package is used but not mandatory. Throws an error if no token is provided and logs verification failures. ```javascript const handleResultFetching = async () => { try { const token = bearerToken; if (!token) { throw new Error('No token provided') } // Fetch JWKS const apiUrl = 'https://api.prod.innerworks.me/api/v1/.well-known/jwks.json'; const keyStore = createRemoteJWKSet(new URL(apiUrl)); // Verify the Token const { payload, protectedHeader } = await compactVerify(token, keyStore); // View Decoded Payload const decodedPayload = JSON.parse(new TextDecoder().decode(payload)); } catch (error) { console.error('Token verification failed:', error); } }; ``` -------------------------------- ### Detailed VPN Detection Response Source: https://docs.innerworks.me/docs/advanced/api-access The detailed VPN response provides comprehensive metadata including detection reasons, provider, and IP addresses. ```json { "geolocation": { "vpnIsEnabled": false, "vpnDetectionReasons": "None", "trueGeoLocationName": "United Kingdom", "trueGeoLocationCode": "GB", "vpnProvider": "...", "vpnLocationCode": "...", "stateUS": "...", "trueUserIpAddress": "...", "requestIpAddress": "..." } } ``` -------------------------------- ### CSP whitelist domain sdk-cdn.prod.innerworks.me Source: https://docs.innerworks.me/docs/getting-started/quickstart Whitelist the SDK CDN domain in your Content Security Policy script-src or default-src directive. If strict CSP is enforced and this domain is not whitelisted, the SDK will fail to load its core components. ```text sdk-cdn.prod.innerworks.me ``` -------------------------------- ### Simple Fingerprinting Response Source: https://docs.innerworks.me/docs/advanced/api-access The simple response format returns a single fingerprint field. ```json { "fingerprinting" : { "fingerprint": "...." } } ``` -------------------------------- ### Angular wrapper for refreshing InnerworksMetrics Source: https://docs.innerworks.me/docs/advanced/refreshing-the-sdk Angular component that initializes InnerworksMetrics in ngAfterViewInit and provides a refresh method. Call this.refresh() to reinitialize the SDK. ```TypeScript import { InnerworksMetrics } from '@innerworks-me/iw-auth-sdk'; innerworksMetrics: InnerworksMetrics | null = null; ngAfterViewInit(): void { this.refresh(); } refresh(): void { this.innerworksMetrics = new InnerworksMetrics({ appId: 'your-project-id' }); } ``` -------------------------------- ### React wrapper for refreshing InnerworksMetrics Source: https://docs.innerworks.me/docs/advanced/refreshing-the-sdk React hook that initializes InnerworksMetrics and provides a refresh function. Use it to reinitialize the SDK when cached data becomes stale. ```TypeScript import { useState, useEffect, useCallback } from 'react'; import { InnerworksMetrics } from '@innerworks-me/iw-auth-sdk'; function useInnerworksMetrics({ appId }: { appId: string }) { const [metrics, setMetrics] = useState(null); const refresh = useCallback(() => { setMetrics(new InnerworksMetrics({ appId })); }, [appId]); useEffect(() => { refresh(); }, [refresh]); return [metrics, refresh] as const; } ``` -------------------------------- ### Handle iframe response with message event Source: https://docs.innerworks.me/docs/advanced/iframe-integration Listens for messages from the Innerworks iframe and calls iframeCallback when the response is valid. The callback should include logic to indicate the page is free to be destroyed, and a timeout is recommended in case the callback fails. ```javascript // script.js function iframeCallback(response) { // Include logic here to indicate the page is now free to be // destroyed. We also recommend including a timeout in case the // callback fails to be sent for some reason or takes too long. } window.addEventListener("message", (event) => { const response = event.data; if ( response && response.source === "innerworks" && response.data.result ) { iframeCallback(response.data); } }); ``` -------------------------------- ### Send metrics with innerworksMetrics.send() Source: https://docs.innerworks.me/docs/getting-started/quickstart Send metrics at the point you want to analyse a user session. The user-id is used to associate data with a user and is typically a UUID, such as a Web3 wallet address or username. Avoid using personal data for the user-id. ```typescript if (innerworksMetrics) { await innerworksMetrics.send('user-id'); } ``` -------------------------------- ### JavaScript usage of refreshInnerworksMetrics Source: https://docs.innerworks.me/docs/advanced/refreshing-the-sdk Usage of the JavaScript refresh function. Call refreshInnerworksMetrics() at any point to reinitialize the SDK. ```JavaScript // call at any point to reinitialise the SDK refreshInnerworksMetrics(); ``` -------------------------------- ### Decode JWT for VPN detection Source: https://docs.innerworks.me/docs/advanced/iframe-integration Extends iframeCallback to decode the detectionResultJwt from the response and extract the vpnIsEnabled flag. The JWT is split into header, payload, and signature; the payload is base64-decoded and parsed. ```javascript function iframeCallback(response) { //... rest of code // Decode JWT for VPN detection const jwt = response.detectionResultJwt; const [headerB64, payloadB64, signature] = jwt.split('.'); // Decode payload const payload = JSON.parse(atob(payloadB64)); const vpnIsEnabled = payload.detectionResult.vpn.vpnIsEnabled; console.log('VPN detection result:', vpnIsEnabled); } ``` -------------------------------- ### Invalid batch size error response Source: https://docs.innerworks.me/docs/advanced/batched-inference-results Error response when the batch_size query parameter is outside the allowed range of 1 to 5000. The cause field identifies the invalid parameter. ```json { "cause": "batch_size", "error": "batch_size must be between 1 and 5000" } ``` -------------------------------- ### Invalid checkpoint error response Source: https://docs.innerworks.me/docs/advanced/batched-inference-results Error response when the checkpoint query parameter is not a valid checkpoint string. The cause field identifies the invalid parameter. ```json { "cause": "checkpoint", "error": "invalid checkpoint string" } ``` -------------------------------- ### Angular usage of refresh method Source: https://docs.innerworks.me/docs/advanced/refreshing-the-sdk Usage of the Angular refresh method. Call this.refresh() at any point to reinitialize the SDK. ```TypeScript // call this.refresh() at any point to reinitialise the SDK this.refresh(); ``` -------------------------------- ### React usage of useInnerworksMetrics Source: https://docs.innerworks.me/docs/advanced/refreshing-the-sdk Usage of the React hook. Call refreshInnerworksMetrics() at any point to reinitialize the SDK. ```TypeScript const [innerworksMetrics, refreshInnerworksMetrics] = useInnerworksMetrics({ appId: 'your-project-id', }); // call refreshInnerworksMetrics() at any point to reinitialise the SDK ``` -------------------------------- ### Decode VPN detection JWT with jwtDecode Source: https://docs.innerworks.me/docs/getting-started/quickstart Decode the JWT returned by the SDK to access VPN detection results. The JWT is decoded using jwtDecode, and the geolocation object provides vpnIsEnabled, trueGeoLocationName, trueGeoLocationCode, vpnLocationCode, and stateUS. The JWT must be validated via a backend connection using a JWKS certificate. ```typescript import { jwtDecode } from 'jwt-decode'; if(innerworksMetrics) { const response: InnerworksResponse = await innerworksMetrics.send('my-user-id'); if(response.result === 'success') { // VPN Result const token = response.detectionResultJwt; if (token) { const decodedResult = jwtDecode(token); const vpnResult = decodedResult.detectionResult.geolocation; const vpnIsEnabled: boolean = vpnResult.vpnIsEnabled; const trueGeoLocationName: string = vpnResult.trueGeoLocationName; // e.g. "United Kingdom" const trueGeoLocationCode: string = vpnResult.trueGeoLocationCode; // e.g. "GB" const vpnLocationCode: string = vpnResult.vpnLocationCode; const stateUS: string = vpnResult.stateUS; } }; }; ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.