Server API

Server API allows you to get information about visitors (using the /visitors endpoint) or about individual events (using the /events endpoint) in a server environment.

Server API is only for server-side usage, it's not intended to be used from the client side, whether it's a browser or a mobile device.

If you want to identify browsers in your web application, read our JS Agent guide.
If you want to identify mobile devices using native mobile SDKs, please read any of the platform guides in the "Mobile devices" sidebar section on the left.

Server API requests do not count toward your monthly plan and are not billed.

Regions

The server API is available in the Global, EU and Asia (Mumbai) regions:

RegionBase URLServer Location
Globalhttps://api.fpjs.ioGlobal
EUhttps://eu.api.fpjs.ioFrankfurt, Germany
Asia (Mumbai)https://ap.api.fpjs.ioMumbai, India

Authentication

There are 2 ways to authenticate with the API: with auth header or with a query parameter. All unauthenticated requests will return HTTP 403 (forbidden) response.

Auth header

This is the recommended way of API authentication. When making an API request, add Auth-API-Key HTTP header with your secret API key.

API key query parameter

This method of authentication is easy to use when you want to test it in the browser. However we don't recommend using it in production.

Example request with an API key query parameter:

// Paste this URL into your browser
// replace the API key with your real secret API key
https://api.fpjs.io/visitors/someVisitorId?api_key=<<apiKey>>

Get visitor history (Identification only)

GET /visitors/:id

api-base-url/visitors/:id

This endpoint allows you to get a history of visits with all available information. Use the visitorId as a URL path parameter. This API method is scoped to a visitor, i.e. all returned information is by visitorId.

Request

Path parameters
ParameterRequired/OptionalTypeDescription
idrequiredstringvisitorId
Query parameters
ParameterRequired/OptionalTypeDescription
request_idoptionalstringFilter events by requestId, see requestId for details.
linked_idoptionalstringFilter events by custom identifier.
limitoptionalnumberLimit scanned results (see limiting for details).
beforeoptionalintegerUsed to paginate results (see pagination for details).

Response

200: OK

// visitor found and recent visits history is available
{
  "visitorId": "Ibk1527CUFmcnjLwIs4A9",
  "visits": [
    {
      "requestId": "0KSh65EnVoB85JBmloQK",
      "incognito": true,
      "linkedId": "somelinkedId",
      "time": "2019-05-21T16:40:13Z",
      // timestamp of the event with millisecond precision
      "timestamp": 1582299576512,
      "url": "https://www.example.com/login",
      "ip": "61.127.217.15",
      "ipLocation": {
        "accuracyRadius": 10,
        "latitude": 49.982,
        "longitude": 36.2566,
        "postalCode": "61202",
        "timezone": "Europe/Dusseldorf",
        "city": {
          "name": "Dusseldorf"
        },
        "continent": {
          "code": "EU",
          "name": "Europe"
        },
        "country": {
          "code": "DE",
          "name": "Germany"
        },
        "subdivisions": [
          {
            "isoCode": "63",
            "name": "North Rhine-Westphalia"
          }
        ],
      },
      "browserDetails": {
        "browserName": "Chrome",
        "browserMajorVersion": "74",
        "browserFullVersion": "74.0.3729",
        "os": "Windows",
        "osVersion": "7",
        "device": "Other",
        "userAgent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) ....",
      },
      "confidence": {
         "score": 0.97
      },
      "visitorFound": true,
      "firstSeenAt": {
         "global": "2022-03-16T11:26:45.362Z",
         "subscription": "2022-03-16T11:31:01.101Z"
      },
      "lastSeenAt": {
        "global": "2022-03-16T11:28:34.023Z",
        "subscription": null
      }
    }
  ],
  // optional, if more results are available for pagination.
  "lastTimestamp": 1582299576512
}

See more information on firstSeenAt/lastSeenAt timestamps here.

// visitorId does not exist
// or has no recorded visits in the available visit history 
{
  "visitorId": "Ibk1527CUFmcnjLwIs4A9",
  "visits": []
}

403: Forbidden

Forbidden. Most likely the API key is incorrect or missing.

{
  "error": "Forbidden (HTTP 403)"
}

429: Too Many Requests

This response code is returned if the limit on secret API key requests per second has been exceeded.

requestId

Every identification event has a unique identifier, associated with it, called requestId. This identifier is returned back into the browser during the identification API call and is also available in API responses.
It is a convenient way to return the exact identification event that you need. When you filter events with requestId, only one event will be returned, because every event has a unique requestId.

linkedId: adding a custom identifier to events

If you need to associate events with your own identifier, use linkedId. You can use it in different scenarios: e.g., identify by sessionID, identify by purchaseID or by your custom transaction number. You should use requestId to get a single event, whereas you should use linkedId to retrieve several events, associated with your custom identifier.

Limit: limiting scanned results

For performance reasons, visitors API first performs events scanning and then filtering. Filtering always happens after the results are scanned.
Limit is a parameter to specify how many events should be scanned.
Results are always returned sorted by the timestamp in descending order (most recent first), so scanning the results limits how many events are scanned back in the past.
By default, the visits API scans 100 events. However you can specify a different limit parameter, to scan fewer or more results. A maximum value of 500 results can be scanned and returned.

After the results were scanned, the filtering is applied to them, e.g., filtering by requestId or by linkedId.

📘

Note

There is a 1MB limitation on the response size for a single request. If a response should exceed 1MB, the response returns the matching items with an additional paginationKey property that can be used in the next request to fetch the next page results.

Using limit example: your website visitor was identified 120 times and 120 events are stored in our database. Last 10 events are associated with a sessionID = 1234ADF; You want to scan last 50 events and filter them by your sessionID = 1234ADF. You can achieve this by using this query:

GET api-base-url/visitors/:visitorId?limit=50&linked_id=1234ADF

Only 10 rows from the most recent 50 will be returned.

Pagination

When more results are available (e.g., you scanned 200 results using limit parameter, but a total of 600 results are available), a special lastTimestamp top-level attribute is added to the response. You should use the value of this attribute, if you want to paginate the results further in the past, to return the events that happened before that timestamp.

Example of using before parameter:

// 1st request, returning most recent 200 events:
GET api-base-url/visitors/:visitorId?limit=200
// Note that the response has lastTimestamp attribute in the response.
// Use that attribute to return the events that happened before, i.e
// next page of 200 events
GET api-base-url/visitors/:visitorId?limit=200&before=1582232027567

Note that pagination happens during scanning of the results, so if you used pagination + filtering, you can have just a few results back, with potentially more results available for pagination. These timestamps are stored with a millisecond precision. When there are no more results available for scanning, the lastTimestamp attribute will not be returned.

Headers

Retry-After

Indicates how long the user should wait before making a follow-up request. The value is non-negative decimal integer indicating the seconds to delay after the response is received.

Node.js SDK

The FingerprintJS Node.js SDK is published using npm for streamlined integration into your existing workflow. Please visit the GitHub repository to learn more.

Get events (Identification + Bot Detection + AEV)

GET /events/:id

api-base-url/events/:id

This endpoint allows you to get events with all the information from each activated product - AEV, BotD and Fingerprinting. Use the requestId as a URL path :id parameter. This API method is scoped to a request, i.e. all returned information is by requestId.

Request

Path parameters
ParameterRequired/OptionalTypeDescription
idrequiredstringrequestId

Response

200: OK

{
  "products": {
    "identification": {
      "data": {
        "visitorId": "Ibk1527CUFmcnjLwIs4A9",
        "requestId": "0KSh65EnVoB85JBmloQK",
        "incognito": true,
        "linkedId": "somelinkedId",
        "time": "2019-05-21T16:40:13Z",
        // timestamp of the event with millisecond precision
        "timestamp": 1582299576512,
        "url": "https://www.example.com/login",
        "ip": "61.127.217.15",
        "ipLocation": {
          "accuracyRadius": 10,
          "latitude": 49.982,
          "longitude": 36.2566,
          "postalCode": "61202",
          "timezone": "Europe/Dusseldorf",
          "city": {
            "name": "Dusseldorf"
          },
          "continent": {
            "code": "EU",
            "name": "Europe"
          },
          "country": {
            "code": "DE",
            "name": "Germany"
          },
          "subdivisions": [
            {
              "isoCode": "63",
              "name": "North Rhine-Westphalia"
            }
          ],
        },
        "browserDetails": {
          "browserName": "Chrome",
          "browserMajorVersion": "74",
          "browserFullVersion": "74.0.3729",
          "os": "Windows",
          "osVersion": "7",
          "device": "Other",
          "userAgent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) ....",
        },
        "confidence": {
           "score": 0.97
        },
        "visitorFound": true,
        "firstSeenAt": {
           "global": "2022-03-16T11:26:45.362Z",
           "subscription": "2022-03-16T11:31:01.101Z"
        },
        "lastSeenAt": {
          "global": "2022-03-16T11:28:34.023Z",
          "subscription": null
        }
      }
    },
    "botd": {
      "data": {
        "bot": {
          "result": "notDetected"
        },
        "url": "https://example.com/login",
        "ip": "61.127.217.15",
        "time": "2019-05-21T16:40:13Z"
      }
    },
    "rootApps": {
      "data": {
        "result": false
      }
    },
    "emulator": {
      "data": {
        "result": false
      }
    }
  }
}
identification.data

See more information on identification.data fields here

botd.data
bot.result

Bot detection result. There are 3 following values:
notDetected - no bot detected.
good - good bot detected, such as Google bot, Baidu Spider, AlexaBot and so on.
bad - bad bot detected, such as Selenium, Puppeteer, Playwright, headless browsers, and so on.

ip

IP address of the requesting browser or bot.

time

Time in UTC when the request from the JS agent was made. We recommend to treat requests that are older than 2 minutes as malicious. Otherwise, request replay attacks are possible.

rootApps.data
result

Returned when AEV (Application Environment Verification) functionality is enabled for a subscription. There are 2 values:
true - Root Management Apps detected (e.g. Magisk)
false - No Root Management Apps detected

Available only for events from Android client. The field will be empty for a browser/iOS event.

emulator.data
result

Returned when AEV (Application Environment Verification) functionality is enabled for a subscription. There are 2 values:
true - Emulated environment detected (e.g. launch inside of AVD)
false - No signs of emulated environment detected

Available only for events from Android client. The field will be empty for a browser/iOS event.

Errors

Common

All common errors, like authorisation or validation errors, would be returned as follows:

{
  "error": {
    "code": "<error-code>",
    "message": "<error-message>"
  }
}
StatusCodeMessageDescription
403TokenRequiredsecret key is requiredAuth-API-Key header is missing or empty.
403TokenNotFoundsecret key is not foundSubscription not found for specified secret key.
403SubscriptionNotActiveforbiddenSubscription is not active.
403WrongRegionwrong regionServer and subscription region differ.
404RequestNotFoundrequest id is not foundRequest not found for specified id.
Identification

If some error occurred during identification, it would be returned as follows:

200: OK

{
  "products": {
    "identification": {
      "error": {
        "code": "<error-code>",
        "message": "<error-message>"
      }
    }
  }
}
CodeMessageDescription
429 Too Many Requeststoo many requestsThe limit on secret API key requests per second has been exceeded.
Failedinternal server errorInternal server error.
BotD

If some error occurred during bot detection, it would be returned as follows:

200: OK

{
  "products": {
    "botd": {
      "error": {
        "code": "<error-code>",
        "message": "<error-message>"
      }
    }
  }
}
AEV

If some error occurred during AEV work, it would be returned as follows:

200: OK

{
  "products": {
    "rootApps": {
      "error": {
        "code": "<error-code>",
        "message": "<error-message>"
      }
    },
    "emulator": {
      "error": {
        "code": "<error-code>",
        "message": "<error-message>"
      }
    }
  }
}
CodeMessageDescription
TooManyRequeststoo many requestsThe limit on secret API key requests per second has been exceeded.
Failedinternal server errorInternal server error.