Skip to content

Commit

Permalink
Merge pull request #77 from fingerprintjs/feature/INTER-19-spa-improv…
Browse files Browse the repository at this point in the history
…ements

[INTER-19] SPA improvements
  • Loading branch information
TheUnderScorer authored Nov 22, 2023
2 parents 64c0b0a + 29bb11f commit c898404
Show file tree
Hide file tree
Showing 4 changed files with 307 additions and 67 deletions.
108 changes: 70 additions & 38 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,25 +16,25 @@
<a href="https://fingerprintjs.github.io/fingerprintjs-pro-spa"><img src="https://img.shields.io/badge/-Documentation-green" alt="Documentation"></a>
</p>


# Fingerprint Pro SPA

[Fingerprint](https://fingerprint.com/) is a device intelligence platform offering 99.5% accurate visitor identification

This library is designed to be used in single-page-application framework wrappers for the Fingerprint Pro JavaScript Agent.
It has multiple built-in caching mechanisms with recommended default settings.
This library is designed to be used in single-page-application framework wrappers for the Fingerprint Pro JavaScript Agent.
It has multiple built-in caching mechanisms with recommended default settings.

If you just need the Fingerprint Pro [JS agent](https://www.npmjs.com/package/@fingerprintjs/fingerprintjs-pro), you can use it directly, without this wrapper. If you're looking for a framework-specific integration, we have dedicated SDKs for [React (including Next, Preact)](https://github.com/fingerprintjs/fingerprintjs-pro-react), [Vue](https://github.com/fingerprintjs/fingerprintjs-pro-vue), [Svelte](https://github.com/fingerprintjs/fingerprintjs-pro-svelte) and [Angular](https://github.com/fingerprintjs/fingerprintjs-pro-angular).

**This SDK works with Fingerprint Pro, it will not work with the open-source FingerprintJS version!**
Learn more about the [difference between Pro and OSS](https://dev.fingerprint.com/docs/pro-vs-open-source).
**This SDK works with Fingerprint Pro, it will not work with the open-source FingerprintJS version!**
Learn more about the [difference between Pro and OSS](https://dev.fingerprint.com/docs/pro-vs-open-source).
If you'd like to have a similar SPA wrapper for the OSS version of FingerprintJS, consider [raising an issue in our issue tracker](https://github.com/fingerprintjs/fingerprintjs-pro-spa/issues).

## Table of Contents

- [Requirements](#requirements)
- [Installation](#installation)
- [Getting Started](#getting-started)
- [Caching](#caching)
- [Support and Feedback](#support-and-feedback)
- [Documentation](#documentation)
- [License](#license)
Expand Down Expand Up @@ -77,23 +77,21 @@ In order to identify visitors you'll need a Fingerprint Pro account (you can [si
Create a `FpjsClient` instance before rendering or initializing your application. You should only have one instance of the client. You need to specify your public API key and other configuration options based on your chosen region and active integration.

```js
import {
FpjsClient,
FingerprintJSPro
} from '@fingerprintjs/fingerprintjs-pro-spa';
import { FpjsClient, FingerprintJSPro } from '@fingerprintjs/fingerprintjs-pro-spa'

// It can receive multiple parameters but the only required one is `loadOptions`,
// which contains the public API key
const fpjsClient = new FpjsClient({
// You can also pass these options later in `.init()` method
loadOptions: {
apiKey: "<PUBLIC_API_KEY>",
apiKey: '<PUBLIC_API_KEY>',
// endpoint: ["<CUSTOM_ENDPOINT>", FingerprintJSPro.defaultEndpoint],
// scriptUrlPattern: ["<CUSTOM_SCRIPT_URL>", FingerprintJSPro.defaultScriptUrlPattern],
// region: "eu"
}
});
},
})
```
You can learn more about different load options in the [JS Agent API Reference](https://dev.fingerprint.com/docs/js-agent#initializing-the-agent).

> [!NOTE]
> You must provide `loadOptions` containing your public API key either in the constructor or in the `init` method. If you don't, the SDK will throw an error. You can learn more about different load options here in the [JS Agent documentation](https://dev.fingerprint.com/docs/js-agent#initializing-the-agent).
### 3. Initialize the JS Agent

Expand All @@ -102,6 +100,7 @@ Before you start making identification requests to the Fingerprint Pro API, you
```js
// with async/await
await fpjsClient.init()

const visitorData = await fpjsClient.getVisitorData()

// with promises
Expand All @@ -110,6 +109,17 @@ const visitorData = fpjsClient.init().then(() => {
})
```

You can also pass the `loadOptions` into the `init` method here. They will be merged with the options passed to the constructor.

```js
await fpjsClient.init({
apiKey: '<PUBLIC_API_KEY>',
// endpoint: ["<CUSTOM_ENDPOINT>", FingerprintJSPro.defaultEndpoint],
// scriptUrlPattern: ["<CUSTOM_SCRIPT_URL>", FingerprintJSPro.defaultScriptUrlPattern],
// region: "eu"
})
```

### 4. Identify visitors

The `getVisitorData` method returns visitor identification data based on the request [options](https://dev.fingerprint.com/docs/js-agent#get-options).
Expand All @@ -126,59 +136,80 @@ const visitorData = fpjsClient.getVisitorData({ extendedResult: true }).then((vi
})
```

See the [JS Agent API reference](https://dev.fingerprint.com/docs/js-agent) for more details.
See the [JS Agent API reference](https://dev.fingerprint.com/docs/js-agent) for more details.

### Caching
## Caching

Fingerprint Pro usage is billed per API call. To avoid unnecessary API calls, it is a good practice to cache identification results. The SDK provides three ways to cache visitor data out of the box:

* Session storage (default) - `sessionStorage`
* Local storage - `localStorage`
* Memory - `memory`
* No cache - `nocache`
- Session storage (default) - `sessionStorage`
- Local storage - `localStorage`
- Memory - `memory`
- No cache - `nocache`

You can specify the `cacheLocation` option when creating the `FpjsClient`:

```js
const fpjsClient = new FpjsClient({
loadOptions: {
apiKey: "your-fpjs-public-api-key"
apiKey: 'your-fpjs-public-api-key',
},
cacheLocation: 'localstorage'
cacheLocation: 'localstorage',
// You can also use the provided TypeScript enum
// cacheLocation: CacheLocation.LocalStorage
});
})
```

Cache keys are based on the combination of _GetOptions_. For example, API responses for calls with `extendedResult: true` and `extendedResult: false` are stored independently.

* You can ignore the cached result for a specific API call by passing `{ ignoreCache: true }` to the `getVisitorData()` method.
* You can also use your custom cache implementation as described below.

> [!NOTE]
> If you use data from [`extendedResult`](https://dev.fingerprint.com/docs/js-agent#extendedresult), pay additional attention to your caching strategy.
> Some fields, for example, `ip` or `lastSeenAt`, might change over time for the same visitor. Use `getVisitorData({ ignoreCache: true })` to fetch the latest identification results.
> If you use data from [`extendedResult`](https://dev.fingerprint.com/docs/js-agent#extendedresult), pay additional attention to your caching strategy. Some fields, for example, `ip` or `lastSeenAt`, might change over time for the same visitor.
You can ignore the cached result for a specific API call and using `{ ignoreCache: true }`:

#### Creating a custom cache
```js
const visitorData = await fpjsClient.getVisitorData({ ignoreCache: true })
```

Check if your response was retrieved from cache using the returned `cacheHit` flag:

```js
const { cacheHit, ...visitorData } = await fpjsClient.getVisitorData()
```

Use `getVisitorDataFromCache` to directly retrieve responses from cache:

```js
// Checks if request matching given options is present in cache
await fpjsClient.isInCache({ extendedResult: true })

// Returns cached visitor data based on the request options, or undefined if the data is not present in cache
const cachedResult = await fpjsClient.getVisitorDataFromCache({ extendedResult: true })
```

You can also use your custom cache implementation as described below.

### Creating a custom cache

The SDK can use a custom cache store implemented inside your application. This is useful when a different data store is more convenient in your environment, such as a hybrid mobile app.

You can provide an object to the `cache` property of the SDK configuration that implements the following functions. All the functions can return a Promise or a static value.

| Signature | Return type | Description |
| -------------------------------- | ------------------------------ |--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `get(key)` | Promise<object> or object | Returns the item from the cache with the specified key, or `undefined` if it was not found |
| `set(key: string, object: any) ` | Promise<void> or void | Sets an item into the cache |
| `remove(key)` | Promise<void> or void | Removes a single item from the cache at the specified key, or no-op if the item was not found |
| Signature | Return type | Description |
| -------------------------------- | ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `get(key)` | Promise<object> or object | Returns the item from the cache with the specified key, or `undefined` if it was not found |
| `set(key: string, object: any) ` | Promise<void> or void | Sets an item into the cache |
| `remove(key)` | Promise<void> or void | Removes a single item from the cache at the specified key, or no-op if the item was not found |
| `allKeys()` | Promise<string[]> or string [] | Returns the list of all keys. By default, the keys we use are prefixed with `@fpjs@client@` but you can pass your own custom prefix as an option when you create the FpjsClient |

> [!NOTE]
> The `cache` property takes priority over `cacheLocation` if both are set. A warning is displayed in the console if that happens.
We export the internal `InMemoryCache`, `LocalStorageCache`, `SessionStorageCache`, and `CacheStub` implementations, so you can wrap your custom cache around these implementations if you wish.

#### Cache time
Use the `cacheTimeInSeconds` client constructor option to set a custom cache time. To ensure high identification accuracy we recommend not to cache visitors data for longer than 24 hours. If you pass a value higher than 86400 (60 * 60 * 24), the `FpjsClient` constructor will throw an error.
### Cache time

Use the `cacheTimeInSeconds` client constructor option to set a custom cache time. To ensure high identification accuracy we recommend not to cache visitors data for longer than 24 hours. If you pass a value higher than 86400 (60 _ 60 _ 24), the `FpjsClient` constructor will throw an error.

## Support and feedback

Expand All @@ -187,6 +218,7 @@ To report problems, ask questions, or provide feedback, please use [Issues](http
## Documentation

This library uses [Fingerprint Pro](https://fingerprint.com/github/) under the hood.

- To learn more about Fingerprint Pro read our [product documentation](https://dev.fingerprint.com/docs).
- To learn more about this SDK, there is a [Typedoc-generated SDK Reference](https://fingerprintjs.github.io/fingerprintjs-pro-spa) available.

Expand Down
Loading

0 comments on commit c898404

Please sign in to comment.