@signap/signals-react-native
v0.1.1
Published
Signap — React Native SDK (visitor identification, cross-platform stitching). Thin bridge over the native iOS/Android SDKs.
Maintainers
Readme
@signap/signals-react-native — React Native SDK (alpha)
Cross-platform React Native SDK that identifies a visitor in one round-trip, returning the resolved visitor id + confidence. Apache-2.0.
Architecture — a thin native bridge (not a re-implementation)
This SDK is a bridge: every JS identify() call is marshalled to the audited
native SDKs — iOS Signap and Android io.signap.sdk. Device-signal
collection, the cross-platform derived ids (supplementary_id/proximity_id),
cert pinning and the /v1/identify transport all run in that native code.
Why bridge instead of re-implementing in JS:
- Parity is guaranteed. Derived-id parity is locked across web↔iOS↔Android by a single shared golden fixture. Bridging means React Native lands in the same visitor bucket as the native apps — re-deriving in JS would risk the drift the fixture exists to prevent.
- Full device signals.
deviceModel,osVersion,vendorId,isEmulator,isRooted, RAM/cores need native APIs anyway; the native SDKs already collect them with zero third-party deps.
Install
npm install @signap/signals-react-native
cd ios && pod installThis SDK ships native code, so it requires a dev build — it does not run in
Expo Go (use expo prebuild / an EAS dev client, or a bare React Native app).
Usage
import { Signap } from "@signap/signals-react-native";
// Configure once (e.g. in your root component). Ship a PUBLIC key only (pk_…).
// `endpoint` is REQUIRED — the SDK ships no baked default host.
const signap = await Signap.load({
apiKey: "pk_live_xxxxxxxx",
endpoint: "https://your-ingest-host.example", // required (e.g. http://10.0.2.2:8080 → a local dev server from the Android emulator)
region: "ap",
});
// Identify. `linkedId` is the cross-platform linkage hint: pass the logged-in
// user id so web + mobile sessions link to the same account.
const result = await signap.identify({ linkedId: currentUserId });
console.log(result.visitorId, result.confidence);Errors throw a typed SignapError with a stable code
(INVALID_CONFIGURATION · NETWORK_ERROR · TIMEOUT · HTTP_ERROR ·
INVALID_RESPONSE · PINNING_FAILED · NATIVE_MODULE_UNAVAILABLE); for
HTTP_ERROR the HTTP status is also set.
Cert pinning (production)
const signap = await Signap.load({
apiKey: "pk_live_xxxxxxxx",
pinnedSpkiHashes: ["base64-sha256-of-server-SPKI"], // empty ⇒ system trust (dev)
});The pin is the SHA-256 of the SubjectPublicKeyInfo (SPKI) DER — the standard form, identical on web / iOS / Android (one pin for all platforms). It is enforced by the native SDK. Compute it from the server cert:
openssl x509 -in server.crt -pubkey -noout \
| openssl pkey -pubin -outform der \
| openssl dgst -sha256 -binary | base64API
| Member | Signature | Notes |
|---|---|---|
| Signap.load(config) | (SignapConfiguration) => Promise<Signap> | Validates apiKey (≥ 8 chars). |
| signap.identify(options?) | (IdentifyOptions) => Promise<IdentifyResult> | Collects signals natively + resolves the visitor. |
SignapConfiguration: { apiKey, endpoint?, region?, timeoutMs?, pinnedSpkiHashes? }
IdentifyOptions: { linkedId?, tag?, extra? }
IdentifyResult: { requestId, ingestedAt, region, visitorId, confidence, identifiedAt }
These mirror the native iOS/Android types one-to-one (the bridge marshals dictionaries ↔ native types).
Native dependency
The bridge calls into the native SDKs:
- iOS — the
SignapSwift package links into your app binary soimport Signapin the bridge resolves; the podspec (Signap.podspec) wires it. - Android — depends on the
io.signap.sdkMaven artifact viaandroid/build.gradle.
What it sends
The native SDK builds a proto3-JSON FingerprintPayload (with a native
MobileSignals block) — the same wire shape as the native iOS/Android apps,
reported with the underlying native SDK's x-sdk-name
(@signap/signals-ios / @signap/signals-android).
Status
Alpha. Public API + native bridge are final.
License
Apache-2.0 — see LICENSE.
