spotny-sdk 1.0.3 → 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -287
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -267,7 +267,7 @@ Returns `Promise<Object>`.
|
|
|
267
267
|
|
|
268
268
|
## How It Works
|
|
269
269
|
|
|
270
|
-
1. `initialize()` sends your `token`, `apiKey`, and `
|
|
270
|
+
1. `initialize()` sends your `token`, `apiKey`, and `identifierId` to the Spotny backend, which issues a session JWT. The JWT is persisted locally and auto-refreshed when it expires.
|
|
271
271
|
2. `startScanner()` begins monitoring for iBeacons with the Spotny UUID.
|
|
272
272
|
3. When a beacon is detected, the SDK fetches the associated campaign from the Spotny backend.
|
|
273
273
|
4. `NEARBY` events are sent automatically as the user moves closer or further.
|
|
@@ -301,289 +301,3 @@ All events are tied to the authenticated `identifierId` supplied during `initial
|
|
|
301
301
|
## License
|
|
302
302
|
|
|
303
303
|
MIT
|
|
304
|
-
|
|
305
|
-
---
|
|
306
|
-
|
|
307
|
-
## Installation
|
|
308
|
-
|
|
309
|
-
```sh
|
|
310
|
-
npm install spotny-sdk
|
|
311
|
-
# or
|
|
312
|
-
yarn add spotny-sdk
|
|
313
|
-
```
|
|
314
|
-
|
|
315
|
-
### iOS
|
|
316
|
-
|
|
317
|
-
```sh
|
|
318
|
-
cd ios && pod install
|
|
319
|
-
```
|
|
320
|
-
|
|
321
|
-
Add the following keys to your `Info.plist`:
|
|
322
|
-
|
|
323
|
-
```xml
|
|
324
|
-
<key>NSLocationWhenInUseUsageDescription</key>
|
|
325
|
-
<string>We use your location to detect nearby points of interest.</string>
|
|
326
|
-
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
|
|
327
|
-
<string>We use your location in the background to detect nearby points of interest.</string>
|
|
328
|
-
<key>NSBluetoothAlwaysUsageDescription</key>
|
|
329
|
-
<string>We use Bluetooth to detect nearby points of interest.</string>
|
|
330
|
-
```
|
|
331
|
-
|
|
332
|
-
Enable **Background Modes** in Xcode → your app target → **Signing & Capabilities** → Background Modes:
|
|
333
|
-
|
|
334
|
-
- ✅ Location updates
|
|
335
|
-
- ✅ Uses Bluetooth LE accessories
|
|
336
|
-
|
|
337
|
-
### Android
|
|
338
|
-
|
|
339
|
-
Add to `AndroidManifest.xml`:
|
|
340
|
-
|
|
341
|
-
```xml
|
|
342
|
-
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
|
|
343
|
-
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
|
|
344
|
-
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
|
345
|
-
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
|
|
346
|
-
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
|
|
347
|
-
```
|
|
348
|
-
|
|
349
|
-
---
|
|
350
|
-
|
|
351
|
-
## Quick Start
|
|
352
|
-
|
|
353
|
-
```tsx
|
|
354
|
-
import { useEffect } from 'react';
|
|
355
|
-
import {
|
|
356
|
-
initialize,
|
|
357
|
-
startScanner,
|
|
358
|
-
stopScanner,
|
|
359
|
-
addBeaconsRangedListener,
|
|
360
|
-
addBeaconRegionListener,
|
|
361
|
-
} from 'spotny-sdk';
|
|
362
|
-
|
|
363
|
-
export default function App() {
|
|
364
|
-
useEffect(() => {
|
|
365
|
-
// 1. Initialize once before anything else
|
|
366
|
-
initialize({
|
|
367
|
-
token: 'YOUR_SDK_TOKEN', // required — from your Spotny dashboard
|
|
368
|
-
source: 'nike',
|
|
369
|
-
maxDetectionDistance: 10,
|
|
370
|
-
});
|
|
371
|
-
|
|
372
|
-
// 2. Listen for nearby beacons
|
|
373
|
-
const beaconSub = addBeaconsRangedListener(({ beacons, region }) => {
|
|
374
|
-
beacons.forEach((b) =>
|
|
375
|
-
console.log(
|
|
376
|
-
`${b.major}/${b.minor} — ${b.distance.toFixed(1)}m (${b.proximity})`
|
|
377
|
-
)
|
|
378
|
-
);
|
|
379
|
-
});
|
|
380
|
-
|
|
381
|
-
// 3. Listen for region enter/exit
|
|
382
|
-
const regionSub = addBeaconRegionListener(({ event, region }) => {
|
|
383
|
-
console.log(`${event.toUpperCase()}: ${region}`);
|
|
384
|
-
});
|
|
385
|
-
|
|
386
|
-
// 4. Start scanning
|
|
387
|
-
startScanner();
|
|
388
|
-
|
|
389
|
-
return () => {
|
|
390
|
-
stopScanner();
|
|
391
|
-
beaconSub.remove();
|
|
392
|
-
regionSub.remove();
|
|
393
|
-
};
|
|
394
|
-
}, []);
|
|
395
|
-
|
|
396
|
-
return null;
|
|
397
|
-
}
|
|
398
|
-
```
|
|
399
|
-
|
|
400
|
-
---
|
|
401
|
-
|
|
402
|
-
## API Reference
|
|
403
|
-
|
|
404
|
-
### Initialization
|
|
405
|
-
|
|
406
|
-
#### `initialize(config)`
|
|
407
|
-
|
|
408
|
-
**Must be called before any other SDK function.** Configures the SDK with your brand settings.
|
|
409
|
-
|
|
410
|
-
| Option | Type | Default | Description |
|
|
411
|
-
| -------------------------- | -------- | ------------ | --------------------------------------------------------------------------------------------------------------- |
|
|
412
|
-
| `token` | `string` | **required** | SDK token issued by Spotny for your app. Verified against the backend — rejects with `UNAUTHORIZED` if invalid. |
|
|
413
|
-
| `source` | `string` | – | Your brand or app identifier (e.g. `'nike'`). Sent with every tracking event. |
|
|
414
|
-
| `maxDetectionDistance` | `number` | `8.0` | Maximum detection radius in metres. Beacons beyond this are ignored. |
|
|
415
|
-
| `distanceCorrectionFactor` | `number` | `0.5` | Multiplier applied to raw RSSI distance. Tune for your beacon TX power. |
|
|
416
|
-
|
|
417
|
-
Returns `Promise<string>`. **Rejects** if the token is missing, invalid, or the network request fails — handle the error before calling `startScanner()`.
|
|
418
|
-
|
|
419
|
-
```ts
|
|
420
|
-
await initialize({
|
|
421
|
-
token: 'YOUR_SDK_TOKEN',
|
|
422
|
-
source: 'nike',
|
|
423
|
-
maxDetectionDistance: 10,
|
|
424
|
-
distanceCorrectionFactor: 0.5,
|
|
425
|
-
});
|
|
426
|
-
```
|
|
427
|
-
|
|
428
|
-
---
|
|
429
|
-
|
|
430
|
-
### Core Scanning
|
|
431
|
-
|
|
432
|
-
#### `startScanner()`
|
|
433
|
-
|
|
434
|
-
Starts iBeacon scanning. The SDK manages a fully anonymous `device_id` internally (stored in Keychain on iOS, SharedPreferences on Android — persists across launches).
|
|
435
|
-
|
|
436
|
-
Returns `Promise<string>`.
|
|
437
|
-
|
|
438
|
-
```ts
|
|
439
|
-
await startScanner();
|
|
440
|
-
```
|
|
441
|
-
|
|
442
|
-
---
|
|
443
|
-
|
|
444
|
-
#### `stopScanner()`
|
|
445
|
-
|
|
446
|
-
Stops scanning and cleans up all per-beacon state (sends `PROXIMITY_EXIT` events for any active beacons).
|
|
447
|
-
|
|
448
|
-
Returns `Promise<string>`.
|
|
449
|
-
|
|
450
|
-
---
|
|
451
|
-
|
|
452
|
-
#### `isScanning()`
|
|
453
|
-
|
|
454
|
-
Returns `Promise<boolean>` — `true` if the scanner is currently active.
|
|
455
|
-
|
|
456
|
-
---
|
|
457
|
-
|
|
458
|
-
### Permissions
|
|
459
|
-
|
|
460
|
-
#### `requestNotificationPermissions()` _(iOS only)_
|
|
461
|
-
|
|
462
|
-
Prompts the user for local notification permission (`alert`, `sound`, `badge`).
|
|
463
|
-
|
|
464
|
-
Returns `Promise<'granted' | 'denied'>`.
|
|
465
|
-
|
|
466
|
-
---
|
|
467
|
-
|
|
468
|
-
### Event Listeners
|
|
469
|
-
|
|
470
|
-
#### `addBeaconsRangedListener(callback)`
|
|
471
|
-
|
|
472
|
-
Fires when the set of nearby beacons changes, or every `debounceInterval` seconds (default 5 s) if nothing changed. The event is **deduplicated** — it does not fire every ranging cycle if proximity is unchanged.
|
|
473
|
-
|
|
474
|
-
```ts
|
|
475
|
-
const sub = addBeaconsRangedListener(({ beacons, region }) => {
|
|
476
|
-
beacons.forEach((b) => {
|
|
477
|
-
console.log(`Major ${b.major} / Minor ${b.minor}`);
|
|
478
|
-
console.log(`Distance: ${b.distance.toFixed(2)}m — ${b.proximity}`);
|
|
479
|
-
console.log(`RSSI: ${b.rssi} dBm`);
|
|
480
|
-
});
|
|
481
|
-
});
|
|
482
|
-
|
|
483
|
-
sub.remove(); // call on cleanup
|
|
484
|
-
```
|
|
485
|
-
|
|
486
|
-
Each beacon in the array:
|
|
487
|
-
|
|
488
|
-
| Field | Type | Description |
|
|
489
|
-
| ----------- | -------- | -------------------------------------------------------------- |
|
|
490
|
-
| `uuid` | `string` | Beacon proximity UUID |
|
|
491
|
-
| `major` | `number` | Beacon major value |
|
|
492
|
-
| `minor` | `number` | Beacon minor value |
|
|
493
|
-
| `distance` | `number` | Estimated distance in metres (after correction factor applied) |
|
|
494
|
-
| `rssi` | `number` | Raw signal strength in dBm |
|
|
495
|
-
| `proximity` | `string` | `'immediate'` \| `'near'` \| `'far'` \| `'unknown'` |
|
|
496
|
-
|
|
497
|
-
---
|
|
498
|
-
|
|
499
|
-
#### `addBeaconRegionListener(callback)`
|
|
500
|
-
|
|
501
|
-
Fires when the user enters or exits a beacon region. Works in foreground, background, and terminated state (iOS).
|
|
502
|
-
|
|
503
|
-
```ts
|
|
504
|
-
const sub = addBeaconRegionListener(({ event, region, state }) => {
|
|
505
|
-
if (event === 'enter') console.log('Entered region', region);
|
|
506
|
-
if (event === 'exit') console.log('Left region', region);
|
|
507
|
-
if (event === 'determined') console.log('State for', region, '→', state);
|
|
508
|
-
});
|
|
509
|
-
|
|
510
|
-
sub.remove(); // call on cleanup
|
|
511
|
-
```
|
|
512
|
-
|
|
513
|
-
| Field | Type | Description |
|
|
514
|
-
| -------- | -------- | ------------------------------------------------------------------ |
|
|
515
|
-
| `event` | `string` | `'enter'` \| `'exit'` \| `'determined'` |
|
|
516
|
-
| `region` | `string` | Region identifier |
|
|
517
|
-
| `state` | `string` | `'inside'` \| `'outside'` \| `'unknown'` (`determined` event only) |
|
|
518
|
-
|
|
519
|
-
---
|
|
520
|
-
|
|
521
|
-
### Debug Helpers
|
|
522
|
-
|
|
523
|
-
#### `getDebugLogs()`
|
|
524
|
-
|
|
525
|
-
Returns the on-device debug log file as a string. Includes campaign fetch results and proximity events sent.
|
|
526
|
-
|
|
527
|
-
Returns `Promise<string>`.
|
|
528
|
-
|
|
529
|
-
#### `clearDebugLogs()`
|
|
530
|
-
|
|
531
|
-
Clears the on-device debug log file.
|
|
532
|
-
|
|
533
|
-
Returns `Promise<string>`.
|
|
534
|
-
|
|
535
|
-
#### `setDebounceInterval(seconds)`
|
|
536
|
-
|
|
537
|
-
Sets how often the `onBeaconsRanged` event is force-emitted even if proximity hasn't changed (default: `5`).
|
|
538
|
-
|
|
539
|
-
```ts
|
|
540
|
-
await setDebounceInterval(10); // emit at most every 10 s
|
|
541
|
-
```
|
|
542
|
-
|
|
543
|
-
#### `clearDebounceCache()`
|
|
544
|
-
|
|
545
|
-
Resets internal campaign-fetch cooldown state. Useful during testing.
|
|
546
|
-
|
|
547
|
-
#### `getDebounceStatus()`
|
|
548
|
-
|
|
549
|
-
Returns internal per-beacon timing state. Useful for debugging stuck campaigns.
|
|
550
|
-
|
|
551
|
-
Returns `Promise<Object>`.
|
|
552
|
-
|
|
553
|
-
---
|
|
554
|
-
|
|
555
|
-
## How It Works
|
|
556
|
-
|
|
557
|
-
1. `initialize()` sets your brand config.
|
|
558
|
-
2. `startScanner()` begins monitoring for iBeacons with the Spotny UUID.
|
|
559
|
-
3. When a beacon is detected, the SDK fetches the associated campaign from the Spotny backend.
|
|
560
|
-
4. `NEARBY` events are sent automatically as the user moves closer or further.
|
|
561
|
-
5. `IMPRESSION_HEARTBEAT` events are sent every 10 s when the user is within 2 m of an active campaign.
|
|
562
|
-
6. On exit, `PROXIMITY_EXIT` is sent and all state is cleaned up.
|
|
563
|
-
|
|
564
|
-
The SDK is **fully anonymous** — it generates a persistent `device_id` (Keychain on iOS, SharedPreferences on Android) that survives app reinstalls. No user identity is collected or sent.
|
|
565
|
-
|
|
566
|
-
---
|
|
567
|
-
|
|
568
|
-
## Platform Support
|
|
569
|
-
|
|
570
|
-
| Feature | iOS | Android |
|
|
571
|
-
| ------------------------ | --- | ------- |
|
|
572
|
-
| iBeacon ranging | ✅ | ✅ |
|
|
573
|
-
| Region enter/exit | ✅ | ✅ |
|
|
574
|
-
| Background scanning | ✅ | ✅ |
|
|
575
|
-
| Terminated-state wakeup | ✅ | ✅ |
|
|
576
|
-
| Keychain device ID | ✅ | – |
|
|
577
|
-
| Notification permissions | ✅ | – |
|
|
578
|
-
|
|
579
|
-
---
|
|
580
|
-
|
|
581
|
-
## Contributing
|
|
582
|
-
|
|
583
|
-
- [Development workflow](CONTRIBUTING.md#development-workflow)
|
|
584
|
-
- [Sending a pull request](CONTRIBUTING.md#sending-a-pull-request)
|
|
585
|
-
- [Code of conduct](CODE_OF_CONDUCT.md)
|
|
586
|
-
|
|
587
|
-
## License
|
|
588
|
-
|
|
589
|
-
MIT
|