Web SDK
Install the JavaScript SDK to embed streak mechanics in any web property.
The Web SDK (@streakdev/web) provides a type-safe way to integrate Streakfox into JavaScript and TypeScript applications.
Package status
@streakdev/web is not published to npm yet. Use the dashboard's generated widget snippet for production installs. The examples below document the private-preview package API.
Quick Start
import { createClient, ensureUserHash, getVisitorId } from "@streakdev/web";
// Create a client (do this once)
const client = createClient({
baseUrl: "https://api.streakfox.com",
});
// Get a stable user identifier
const userHash = ensureUserHash(undefined, currentUser?.id ?? getVisitorId());
// Record an event
await client.recordEvent({
projectId: "YOUR_PROJECT_ID",
event: "like",
userHash,
});API Reference
createClient(options)
Creates a Streakfox API client.
const client = createClient({
baseUrl: "https://api.streakfox.com", // API endpoint
adminToken: "sk_...", // Optional: for server-side aliasUser calls
aliasToken: "short-lived-signed-token", // Optional: reveals protected browser rewards
serverIngestToken: "srv_...", // Optional: recommended for server-side /v1/e
});Options:
baseUrl— API endpoint (defaults to production)adminToken— Required foraliasUser()(server-side only)aliasToken— Short-lived project-scoped identity proof used bygetState()for protected reward valuesserverIngestToken— Recommended for server-siderecordEvent()calls that do not send anOriginheaders— Custom headers to include in requests
client.recordEvent(input)
Records a streak event for a user.
await client.recordEvent({
projectId: "proj_abc123", // Required: your project ID
event: "like", // Required: action type
userHash: "user_hash_here", // Required: user identifier
meta: { postId: "123" }, // Optional: custom metadata
idempotencyKey: "unique-id", // Optional: prevent duplicates
});Input fields:
| Field | Type | Required | Description |
|---|---|---|---|
projectId | string | ✅ | Your project ID from the dashboard |
event | string | ✅ | The action type (e.g., 'like', 'visit', 'purchase') |
kind | string | ❌ | Compatibility alias for event |
userHash | string | ✅ | Unique user identifier (use ensureUserHash) |
meta | object | ❌ | Custom metadata attached to the event |
idempotencyKey | string | ❌ | Prevents duplicate processing |
sessionId | string | ❌ | Group events by session |
client.getState(input)
Fetches the current widget state for a user.
const state = await client.getState({
projectId: "proj_abc123",
userHash: "user_hash_here",
event: "like",
identityToken: "short-lived-signed-token", // Or set aliasToken on the client
});
console.log(state.streak.current); // Current streak count
console.log(state.streak.best); // Best streak ever
console.log(state.week); // Last 7 days activityclient.aliasUser(input) (Server-side only)
Links an anonymous visitor to an authenticated user. This merges their streak history.
// Requires adminToken in client options
await client.aliasUser({
projectId: "proj_abc123",
anonymousId: "anon_visitor_id",
userHash: "authenticated_user_hash",
});⚠️ This requires an
adminTokenand should only be called from your server, not client-side code.
client.aliasUserWithToken(input)
Links the browser's anonymous visitor to a signed-in user with a short-lived project-scoped token. The client includes the project key in the request URL for project-aware CORS and sends the signed token in the body.
await client.aliasUserWithToken({
projectId: "proj_abc123",
token: tokenCreatedOnYourServer,
});Repeating the same binding is safe. Trying to bind that anonymous visitor to a different user returns 409 ALIAS_IDENTITY_CONFLICT.
Helper Functions
ensureUserHash(knownHash?, fallbackId?)
Selects an existing identifier or a persistent anonymous browser ID. Despite the legacy function name, it does not cryptographically hash a supplied fallback ID. Create signed-in user hashes on your server.
import { ensureUserHash, getVisitorId } from "@streakdev/web";
// For anonymous users
const hash = ensureUserHash(undefined, getVisitorId());
// For authenticated users, supply a pseudonymous hash created on your server
const hash = ensureUserHash(userHashFromServer);getVisitorId()
Returns a persistent anonymous visitor ID stored in localStorage.
import { getVisitorId } from "@streakdev/web";
const visitorId = getVisitorId(); // e.g., "v_abc123..."React Integration
Custom Hook Example
import { createClient, ensureUserHash, getVisitorId } from "@streakdev/web";
import { useCallback, useMemo } from "react";
const PROJECT_ID = process.env.NEXT_PUBLIC_STREAK_PROJECT_ID!;
export function useStreak(userId?: string) {
const client = useMemo(() => createClient({ baseUrl: "https://api.streakfox.com" }), []);
const userHash = useMemo(() => ensureUserHash(undefined, userId ?? getVisitorId()), [userId]);
const recordEvent = useCallback(
(event: string, meta?: Record<string, unknown>) =>
client.recordEvent({ projectId: PROJECT_ID, event, userHash, meta }),
[client, userHash],
);
const getState = useCallback(
(event: string) => client.getState({ projectId: PROJECT_ID, event, userHash }),
[client, userHash],
);
return { recordEvent, getState, userHash };
}Usage
function LikeButton({ postId }: { postId: string }) {
const { recordEvent } = useStreak(user?.id);
const handleLike = async () => {
await likePost(postId);
await recordEvent("like", { postId });
};
return <button onClick={handleLike}>Like</button>;
}Server-Side Usage (Node.js)
import { createClient } from "@streakdev/web";
const client = createClient({
baseUrl: "https://api.streakfox.com",
adminToken: process.env.STREAK_ADMIN_TOKEN, // For aliasUser
});
// Record server-side events
export async function recordPurchase(userId: string, orderId: string) {
await client.recordEvent({
projectId: process.env.STREAK_PROJECT_ID!,
event: "purchase",
userHash: hashUserId(userId),
meta: { orderId },
});
}
// Merge anonymous to authenticated user
export async function onUserLogin(anonymousId: string, userId: string) {
await client.aliasUser({
projectId: process.env.STREAK_PROJECT_ID!,
anonymousId,
userHash: hashUserId(userId),
});
}Next Steps
- Action-Based Streaks — Trigger streaks from code
- Connecting Users — Merge anonymous and authenticated users
- Events API — Direct REST API access