From 9531082f190643dc661815109689a244d69582d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20=C5=BBydek?= Date: Thu, 24 Sep 2026 11:18:34 +0200 Subject: [PATCH 01/12] refactor: remove unused error codes --- .../java/com/fingerprint/reactnative/RNFingerprintModule.kt | 2 -- sdk/ios/FPError+React.swift | 2 -- sdk/src/errors.ts | 1 - 3 files changed, 5 deletions(-) diff --git a/sdk/android/src/main/java/com/fingerprint/reactnative/RNFingerprintModule.kt b/sdk/android/src/main/java/com/fingerprint/reactnative/RNFingerprintModule.kt index c1e8452b..7bec6a6b 100644 --- a/sdk/android/src/main/java/com/fingerprint/reactnative/RNFingerprintModule.kt +++ b/sdk/android/src/main/java/com/fingerprint/reactnative/RNFingerprintModule.kt @@ -15,7 +15,6 @@ import com.fingerprint.android.RequestTimeout import com.fingerprint.android.TooManyRequest import com.fingerprint.android.WrongRegion import com.fingerprint.android.SubscriptionNotActive -import com.fingerprint.android.SubscriptionNotFound import com.fingerprint.android.SubscriptionRestricted import com.fingerprint.android.InstallationMethodRestricted import com.fingerprint.android.EnvironmentRestricted @@ -132,7 +131,6 @@ class RNFingerprintModule(reactContext: ReactApplicationContext) : NativeRNFinge is TooManyRequest -> "too_many_requests" is WrongRegion -> "wrong_region" is SubscriptionNotActive -> "subscription_not_active" - is SubscriptionNotFound -> "subscription_not_found" is SubscriptionRestricted -> "subscription_restricted" is InstallationMethodRestricted -> "installation_method_restricted" is EnvironmentRestricted -> "environment_restricted" diff --git a/sdk/ios/FPError+React.swift b/sdk/ios/FPError+React.swift index a41bc314..016b21dd 100644 --- a/sdk/ios/FPError+React.swift +++ b/sdk/ios/FPError+React.swift @@ -88,7 +88,6 @@ extension APIError { case .visitorNotFound: return "visitor_not_found" case .tooManyRequests: return "too_many_requests" case .failed: return "failed" - case .eventNotFound: return "event_not_found" case .missingModule: return "missing_module" case .payloadTooLarge: return "payload_too_large" case .serviceUnavailable: return "service_unavailable" @@ -97,7 +96,6 @@ extension APIError { case .invalidProxyIntegrationHeaders: return "invalid_proxy_integration_headers" case .subscriptionRestricted: return "subscription_restricted" case .environmentRestricted: return "environment_restricted" - case .subscriptionNotFound: return "subscription_not_found" case .installationMethodRestricted: return "installation_method_restricted" // A future SDK may add codes; fall back to the raw value rather than losing the information. @unknown default: return code.rawValue diff --git a/sdk/src/errors.ts b/sdk/src/errors.ts index 2b421633..bd7b9a46 100644 --- a/sdk/src/errors.ts +++ b/sdk/src/errors.ts @@ -27,7 +27,6 @@ export type ErrorCode = | 'wrong_region' | 'feature_not_enabled' | 'visitor_not_found' - | 'event_not_found' | 'missing_module' | 'payload_too_large' | 'service_unavailable' From 043e06c165fbb5168a60f4b070ca8a9130614dfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20=C5=BBydek?= Date: Thu, 24 Sep 2026 11:22:22 +0200 Subject: [PATCH 02/12] ci: deploy docs and coverage via shared pages workflow --- .github/workflows/docs-and-coverage.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/docs-and-coverage.yml b/.github/workflows/docs-and-coverage.yml index 205bca0b..5fef1cae 100644 --- a/.github/workflows/docs-and-coverage.yml +++ b/.github/workflows/docs-and-coverage.yml @@ -9,7 +9,7 @@ jobs: generate-docs-and-coverage: name: Generate docs and coverage report uses: fingerprintjs/dx-team-toolkit/.github/workflows/docs-and-coverage.yml@v1 - with: - prepare-gh-pages-commands: | - mv docs/* ./gh-pages - mv coverage/lcov-report ./gh-pages/coverage + permissions: + contents: read + pages: write + id-token: write From 250383d0e5093c0d8e10f80d9f632f66b285417f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20=C5=BBydek?= Date: Thu, 24 Sep 2026 11:26:59 +0200 Subject: [PATCH 03/12] chore: update to changesets-native-dependency-format v0.2.0 --- .changeset/config.json | 12 +++++++++--- package.json | 2 +- pnpm-lock.yaml | 12 +++++++----- 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/.changeset/config.json b/.changeset/config.json index b3e38b7c..09d18e8f 100644 --- a/.changeset/config.json +++ b/.changeset/config.json @@ -4,9 +4,15 @@ "@fingerprintjs/changesets-native-dependency-format", { "repo": "fingerprintjs/react-native", - "androidPath": "sdk/android", - "iosPodspecPath": "sdk/RNFingerprint.podspec", - "packageName": "@fingerprint/react-native" + "packageName": "@fingerprint/react-native", + "ios": { + "podspecPath": "sdk/RNFingerprint.podspec", + "dependencyName": "Fingerprint-iOS" + }, + "android": { + "path": "sdk/android", + "gradleTaskName": "printFingerprintNativeSDKVersion" + } } ], "commit": false, diff --git a/package.json b/package.json index 4c99dc37..1f7d977b 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@changesets/types": "^6.1.0", "@commitlint/cli": "^21.2.1", "@eslint-react/eslint-plugin": "^5.16.1", - "@fingerprintjs/changesets-native-dependency-format": "^0.1.0", + "@fingerprintjs/changesets-native-dependency-format": "^0.2.0", "@fingerprintjs/commit-lint-dx-team": "^0.1.0", "@fingerprintjs/eslint-config-dx-team": "^3.0.0", "@fingerprintjs/prettier-config-dx-team": "^0.3.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index abf617d8..c7f5f517 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -24,8 +24,8 @@ importers: specifier: ^5.16.1 version: 5.16.1(eslint@10.7.0(jiti@2.6.1))(typescript@6.0.3) '@fingerprintjs/changesets-native-dependency-format': - specifier: ^0.1.0 - version: 0.1.0 + specifier: ^0.2.0 + version: 0.2.0 '@fingerprintjs/commit-lint-dx-team': specifier: ^0.1.0 version: 0.1.0 @@ -1306,8 +1306,8 @@ packages: '@fingerprintjs/changesets-changelog-format@0.2.0': resolution: {integrity: sha512-1jI+J1r8OKUtjlFfQW4bmQ8u4E1097zPaKw5fUCgAcahLPgwW4Ae+Keoc253CSyyaKgTu2v/wniUGchmPaXAsg==} - '@fingerprintjs/changesets-native-dependency-format@0.1.0': - resolution: {integrity: sha512-fRrunw8LFXjKEFGWxSB/LG1/0GRkZARKNEs1Zuz9rOSDsJdjzhsYnv1Bo0IEkv7tTCTTJk69oAXGYFOXtWfHeg==} + '@fingerprintjs/changesets-native-dependency-format@0.2.0': + resolution: {integrity: sha512-wUh8Zg+veIPyLs8YWl1AOb1ARUy0F+Yw2ak1Cr0n2U3QCXlZPZ7lTt24DmKSoOgqbA4ZQqu2DOupgsNajkgOog==} '@fingerprintjs/commit-lint-dx-team@0.1.0': resolution: {integrity: sha512-MSYn4bRt9Iyob8hB3Oc/IXz3O8DA2E3ccqlG46pYYhdF090W6u9BNa9uCaVg611FUzqMU41+vs8ztXLkICbKkw==} @@ -2071,10 +2071,12 @@ packages: '@xmldom/xmldom@0.8.13': resolution: {integrity: sha512-KRYzxepc14G/CEpEGc3Yn+JKaAeT63smlDr+vjB8jRfgTBBI9wRj/nkQEO+ucV8p8I9bfKLWp37uHgFrbntPvw==} engines: {node: '>=10.0.0'} + deprecated: this version has critical issues, please update to the latest version '@xmldom/xmldom@0.9.10': resolution: {integrity: sha512-A9gOqLdi6cV4ibazAjcQufGj0B1y/vDqYrcuP6d/6x8P27gRS8643Dj9o1dEKtB6O7fwxb2FgBmJS2mX7gpvdw==} engines: {node: '>=14.6'} + deprecated: this version has critical issues, please update to the latest version abab@2.0.6: resolution: {integrity: sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==} @@ -7550,7 +7552,7 @@ snapshots: dependencies: '@changesets/types': 6.1.0 - '@fingerprintjs/changesets-native-dependency-format@0.1.0': + '@fingerprintjs/changesets-native-dependency-format@0.2.0': dependencies: '@changesets/get-release-plan': 4.0.16 '@changesets/types': 6.1.0 From a93ed170c7fc122feca8e46b57db2a044eccb1c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20=C5=BBydek?= Date: Thu, 24 Sep 2026 11:27:30 +0200 Subject: [PATCH 04/12] refactor(sdk): use `description` instead of `localizedDescription` --- sdk/ios/FPError+React.swift | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sdk/ios/FPError+React.swift b/sdk/ios/FPError+React.swift index 016b21dd..b516d69e 100644 --- a/sdk/ios/FPError+React.swift +++ b/sdk/ios/FPError+React.swift @@ -41,13 +41,13 @@ extension FPError { var reactMessage: String { switch self { case .apiError(let apiError): - return apiError.message ?? self.localizedDescription + return apiError.message ?? self.description case .networkError(let networkError): - return networkError.localizedDescription + return networkError.description case .jsonParsingError(let jsonParsingError): - return jsonParsingError.localizedDescription + return jsonParsingError.description default: - return self.localizedDescription + return self.description } } From 32beab3f7e1a5799bebceb9c1f44c5ea812e4e28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20=C5=BBydek?= Date: Thu, 24 Sep 2026 16:26:10 +0200 Subject: [PATCH 05/12] refactor(sdk): use `localizedDescription` when it's the only one available --- sdk/ios/FPError+React.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sdk/ios/FPError+React.swift b/sdk/ios/FPError+React.swift index b516d69e..697ab0b8 100644 --- a/sdk/ios/FPError+React.swift +++ b/sdk/ios/FPError+React.swift @@ -43,9 +43,9 @@ extension FPError { case .apiError(let apiError): return apiError.message ?? self.description case .networkError(let networkError): - return networkError.description + return networkError.localizedDescription case .jsonParsingError(let jsonParsingError): - return jsonParsingError.description + return jsonParsingError.localizedDescription default: return self.description } From 623fd3cc07aa373bd87130ae06856eaba5259aa4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20=C5=BBydek?= Date: Fri, 25 Sep 2026 15:13:31 +0200 Subject: [PATCH 06/12] docs(sdk): document custom endpoints configuration --- README.md | 6 ++++++ sdk/README.md | 6 ++++++ sdk/src/FingerprintClient.web.ts | 5 ++++- 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 9077bc86..ec27667d 100644 --- a/README.md +++ b/README.md @@ -363,6 +363,12 @@ return ( ) ``` +### Custom endpoints + +To avoid ad blockers, proxy identification through a [proxy integration](https://docs.fingerprint.com/docs/protecting-the-javascript-agent-from-adblockers). Pass identification URLs as `endpoints`, first to last. + +We recommend including the default API URL for your [region](https://docs.fingerprint.com/docs/regions) as a fallback: `https://api.fpjs.io` (US), `https://eu.api.fpjs.io` (EU), `https://ap.api.fpjs.io` (Asia). There are no fallbacks by default. + ## API Reference See the full [generated API Reference](https://fingerprintjs.github.io/react-native/). diff --git a/sdk/README.md b/sdk/README.md index 9077bc86..ec27667d 100644 --- a/sdk/README.md +++ b/sdk/README.md @@ -363,6 +363,12 @@ return ( ) ``` +### Custom endpoints + +To avoid ad blockers, proxy identification through a [proxy integration](https://docs.fingerprint.com/docs/protecting-the-javascript-agent-from-adblockers). Pass identification URLs as `endpoints`, first to last. + +We recommend including the default API URL for your [region](https://docs.fingerprint.com/docs/regions) as a fallback: `https://api.fpjs.io` (US), `https://eu.api.fpjs.io` (EU), `https://ap.api.fpjs.io` (Asia). There are no fallbacks by default. + ## API Reference See the full [generated API Reference](https://fingerprintjs.github.io/react-native/). diff --git a/sdk/src/FingerprintClient.web.ts b/sdk/src/FingerprintClient.web.ts index 017262d7..2581348e 100644 --- a/sdk/src/FingerprintClient.web.ts +++ b/sdk/src/FingerprintClient.web.ts @@ -1,6 +1,7 @@ import * as Fingerprint from '@fingerprint/agent' import type { FingerprintClient, FingerprintResponse, GetOptions, StartOptions } from './types' import { unwrapError } from './unwrapError' +import { isTruthy } from './utils' const packageVersion = '__VERSION__' @@ -13,7 +14,9 @@ const packageVersion = '__VERSION__' class WebFingerprintClient implements FingerprintClient { private readonly agent: Fingerprint.Agent - constructor({ apiKey, region, endpoints, web }: StartOptions) { + constructor({ apiKey, region, endpoints: endpointsParam, web }: StartOptions) { + const endpoints = isTruthy(endpointsParam) ? Fingerprint.withoutDefault(endpointsParam) : endpointsParam + this.agent = Fingerprint.start({ apiKey, region, From 2f598800c97401172e010c27b654153ab1aa9901 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20=C5=BBydek?= Date: Fri, 25 Sep 2026 21:10:02 +0200 Subject: [PATCH 07/12] docs: add usage example for custom endpoints in README --- README.md | 14 ++++++++++++++ sdk/README.md | 14 ++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/README.md b/README.md index ec27667d..f902a8bc 100644 --- a/README.md +++ b/README.md @@ -369,6 +369,20 @@ To avoid ad blockers, proxy identification through a [proxy integration](https:/ We recommend including the default API URL for your [region](https://docs.fingerprint.com/docs/regions) as a fallback: `https://api.fpjs.io` (US), `https://eu.api.fpjs.io` (EU), `https://ap.api.fpjs.io` (Asia). There are no fallbacks by default. + +```javascript +return ( + + + +) +``` + ## API Reference See the full [generated API Reference](https://fingerprintjs.github.io/react-native/). diff --git a/sdk/README.md b/sdk/README.md index ec27667d..f902a8bc 100644 --- a/sdk/README.md +++ b/sdk/README.md @@ -369,6 +369,20 @@ To avoid ad blockers, proxy identification through a [proxy integration](https:/ We recommend including the default API URL for your [region](https://docs.fingerprint.com/docs/regions) as a fallback: `https://api.fpjs.io` (US), `https://eu.api.fpjs.io` (EU), `https://ap.api.fpjs.io` (Asia). There are no fallbacks by default. + +```javascript +return ( + + + +) +``` + ## API Reference See the full [generated API Reference](https://fingerprintjs.github.io/react-native/). From aa89d9f45e87987d3e6a103fee08936662d280bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20=C5=BBydek?= Date: Mon, 28 Sep 2026 14:52:44 +0200 Subject: [PATCH 08/12] ci(workflows): fix package install command in e2e-tests workflow --- .github/workflows/e2e-tests.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/e2e-tests.yml b/.github/workflows/e2e-tests.yml index 7d36e079..0f4f952d 100644 --- a/.github/workflows/e2e-tests.yml +++ b/.github/workflows/e2e-tests.yml @@ -59,7 +59,7 @@ jobs: REACT_NATIVE_VERSION: ${{ matrix.react-native }} - name: Install ${{github.event.release.tag_name}} version of the package - run: pnpm add @fingerprint/react-native@${{github.event.release.tag_name}} + run: pnpm add ${{github.event.release.tag_name}} if: github.event_name == 'release' working-directory: e2e-app @@ -259,7 +259,7 @@ jobs: REACT_NATIVE_VERSION: ${{ matrix.react-native }} - name: Install ${{github.event.release.tag_name}} version of the package - run: pnpm add @fingerprint/react-native@${{github.event.release.tag_name}} + run: pnpm add ${{github.event.release.tag_name}} if: github.event_name == 'release' working-directory: e2e-app @@ -410,7 +410,7 @@ jobs: working-directory: e2e-app - name: Install ${{github.event.release.tag_name}} version of the package - run: pnpm add @fingerprint/react-native@${{github.event.release.tag_name}} + run: pnpm add ${{github.event.release.tag_name}} if: github.event_name == 'release' working-directory: e2e-app From 6d734adba84e2c36dfa995e22a540dc4dee9e19a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20=C5=BBydek?= Date: Mon, 28 Sep 2026 16:46:02 +0200 Subject: [PATCH 09/12] chore(sdk): bump native deps to v4.1.0 --- sdk/Package.swift | 2 +- sdk/RNFingerprint.podspec | 2 +- sdk/android/fingerprint.gradle | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sdk/Package.swift b/sdk/Package.swift index e56bf3a7..166adebb 100644 --- a/sdk/Package.swift +++ b/sdk/Package.swift @@ -68,7 +68,7 @@ let package = Package( .package(name: "React-GeneratedCode", path: "../../../ios"), .package( url: "https://github.com/fingerprintjs/fingerprint-ios", - from: "4.0.0" + .upToNextMinor(from: "4.1.0") ), ], targets: [ diff --git a/sdk/RNFingerprint.podspec b/sdk/RNFingerprint.podspec index 0a064222..6800c9ad 100644 --- a/sdk/RNFingerprint.podspec +++ b/sdk/RNFingerprint.podspec @@ -20,7 +20,7 @@ Pod::Spec.new do |s| # s.requires_arc = true s.dependency "React-Core" - s.dependency "Fingerprint-iOS", "~> 4.0" + s.dependency "Fingerprint-iOS", "~> 4.1.0" # Wires up the TurboModule/Codegen dependencies (ReactCommon, generated specs, ...) and defines # `RCT_NEW_ARCH_ENABLED` for the pod when the app is built with the New Architecture. diff --git a/sdk/android/fingerprint.gradle b/sdk/android/fingerprint.gradle index 59ec6719..b752995f 100644 --- a/sdk/android/fingerprint.gradle +++ b/sdk/android/fingerprint.gradle @@ -1,4 +1,4 @@ -ext.fingerprint_native_sdk_version = "[4.1.0, 5.0.0)" +ext.fingerprint_native_sdk_version = "[4.1.0, 4.2.0)" task printFingerprintNativeSDKVersion { doLast { From 7e4437c344b259690dcb9af435cc8dafe39384ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20=C5=BBydek?= Date: Tue, 29 Sep 2026 08:52:48 +0200 Subject: [PATCH 10/12] chore: exit pre-release mode --- .changeset/pre.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/pre.json b/.changeset/pre.json index 0bfe8cfb..1881f128 100644 --- a/.changeset/pre.json +++ b/.changeset/pre.json @@ -1,5 +1,5 @@ { - "mode": "pre", + "mode": "exit", "tag": "rc", "initialVersions": { "@fingerprint/react-native": "3.17.0" From e9118279cf390720a01df0ddbfeb1c501c8d93f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20=C5=BBydek?= Date: Tue, 29 Sep 2026 13:44:39 +0200 Subject: [PATCH 11/12] fix(sdk): conditionally apply React Gradle plugin in build config --- sdk/android/build.gradle | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sdk/android/build.gradle b/sdk/android/build.gradle index 036f44c4..465be05f 100644 --- a/sdk/android/build.gradle +++ b/sdk/android/build.gradle @@ -5,7 +5,11 @@ plugins { // The SDK supports the New Architecture only. Applying the React Gradle plugin runs library Codegen // (generates the `NativeRNFingerprintSpec` base class). -apply plugin: 'com.facebook.react' +// Only apply when evaluated as a subproject of a host RN app; when run standalone (e.g. CLI tasks like +// printFingerprintNativeSDKVersion), project == rootProject and the React plugin is not on the classpath. +if (project != rootProject) { + apply plugin: 'com.facebook.react' +} apply from: 'fingerprint.gradle' From df2e2c801aa4920c5b64baf8a405e729111b4408 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Przemys=C5=82aw=20=C5=BBydek?= Date: Wed, 30 Sep 2026 10:16:35 +0200 Subject: [PATCH 12/12] refactor(sdk): add `isEmptyArray` utility and integrate it --- sdk/src/FingerprintClient.web.ts | 7 +++++-- sdk/src/utils.ts | 4 ++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/sdk/src/FingerprintClient.web.ts b/sdk/src/FingerprintClient.web.ts index 2581348e..2edf69c0 100644 --- a/sdk/src/FingerprintClient.web.ts +++ b/sdk/src/FingerprintClient.web.ts @@ -1,7 +1,7 @@ import * as Fingerprint from '@fingerprint/agent' import type { FingerprintClient, FingerprintResponse, GetOptions, StartOptions } from './types' import { unwrapError } from './unwrapError' -import { isTruthy } from './utils' +import { isEmptyArray, isTruthy } from './utils' const packageVersion = '__VERSION__' @@ -15,7 +15,10 @@ class WebFingerprintClient implements FingerprintClient { private readonly agent: Fingerprint.Agent constructor({ apiKey, region, endpoints: endpointsParam, web }: StartOptions) { - const endpoints = isTruthy(endpointsParam) ? Fingerprint.withoutDefault(endpointsParam) : endpointsParam + const endpoints = + isTruthy(endpointsParam) && !isEmptyArray(endpointsParam) + ? Fingerprint.withoutDefault(endpointsParam) + : endpointsParam this.agent = Fingerprint.start({ apiKey, diff --git a/sdk/src/utils.ts b/sdk/src/utils.ts index 833c17b6..93b2b071 100644 --- a/sdk/src/utils.ts +++ b/sdk/src/utils.ts @@ -6,6 +6,10 @@ export function isTruthy(value?: T | null): value is T { return Boolean(value) } +export function isEmptyArray(value: unknown): value is [] { + return Array.isArray(value) && value.length === 0 +} + function isObject(value: unknown): value is Record { return typeof value === 'object' && value !== null }