GET /api/context
Available request observations; enrichment is optional
enrich- 1 · optional query parameter
Record interest evidence from your app’s agent. Read permitted profiles when choosing ads for separate placements.
Developer preview. The profile gateway runs locally; public account and key provisioning is still being built.
Installing a website ad placement by hand? Open the developer console to create a test placement, copy two lines of code and watch the install check pass.
Give your coding agent the integration instructions, or follow the guide below.
Copy the installation prompt above into the coding agent working in your application. It describes the signal hooks, permission bindings and separate ad placement to implement.
For the examples below, save the server adapter, taxonomy.json and client.mjs in the same backend directory. Set BEACON_API_ORIGIN, BEACON_API_KEY and BEACON_SUBJECT from your local provisioner. The subject must match a grant for this app; in production, resolve it from the authenticated session.
import { BeaconAgentClient } from './agent.mjs';
export function required(name) {
const value = process.env[name];
if (!value) throw new Error('Set ' + name + ' on the backend.');
return value;
}
export const subject = required('BEACON_SUBJECT');
export const beacon = new BeaconAgentClient({
origin: required('BEACON_API_ORIGIN'),
apiKey: required('BEACON_API_KEY'),
});npm run agent:check
cargo build --locked --offline --bin beacon-profiles
node ops/agent-gateway.mjs /private/config.json /private/profiles.jsonThe gateway listens on 127.0.0.1:8958. Keep its configuration and state outside public assets.
Submit evidence from a user statement or action through the host’s durable backend queue. Return the agent’s response without waiting for Beacon.
This local fixture records tennis affinity. Set BEACON_EVENT_ID to a stable ID and BEACON_GRANT_ID to its provisioned grant. Use the same event ID when retrying; changing content under that ID is rejected.
import { beacon, subject, required } from './client.mjs';
const receipt = await beacon.track({
schemaVersion: 1,
id: required('BEACON_EVENT_ID'),
grantId: required('BEACON_GRANT_ID'),
appSubjectId: subject,
conversationId: 'local-tennis-example',
topicId: 'sports.tennis',
kind: 'affinity',
origin: 'user_statement',
about: 'user',
confidence: 0.9,
observedAtMs: Date.now(),
expiresAtMs: Date.now() + 30 * 24 * 60 * 60 * 1000,
evidenceRef: 'local-example-turn-1',
});
console.log(JSON.stringify(receipt, null, 2));In a host integration, bind identity and grant in trusted code. Replace the fixture conversation and evidence reference with opaque host references. Send structured evidence rather than conversation text.
A statement about another person, a hypothetical question or agent-authored text cannot establish a user interest. An ad response retains its own origin and lower weighting.
Search eligible category labels, IDs and source paths. Use the returned ID in an event.
998 eligible categories
The catalog has 1,013 IDs, with 998 eligible for profiles. It includes 154 Google affinity and 779 in-market source paths. Catalog coverage does not measure recognition accuracy; imported entries have no automatic keyword classifier. Authenticated Meta IDs are not available.
Affinity lasts at most 90 days and intent 14 days. Scores decay with half-lives of 21 and 3 days. Confidence is a host assertion rather than a calibrated probability.
Fetch an ads profile from your backend when choosing an ad for a separate placement.
import { beacon, subject } from './client.mjs';
const profile = await beacon.profile(subject, 'ads');
console.log(JSON.stringify(profile, null, 2));Synthetic tennis fixture. Scores decay; your values depend on the permitted evidence.
{
"taxonomyVersion": "beacon-interests-3",
"asOfMs": 1794002400000,
"purpose": "ads",
"topics": [
{
"topicId": "sports.tennis",
"label": "Tennis",
"kind": "affinity",
"score": 0.9,
"evidenceCount": 1,
"supportingApps": 1,
"lastObservedAtMs": 1794002400000,
"expiresAtMs": 1796594400000
}
]
}adspersonalizationCross-app evidenceA successful empty profile has topics: []. Use your contextual fallback when there is no permitted, unexpired evidence.
A missing or expired subject grant is a domain rejection (400). An invalid app key returns 401. Keep the host usable if the request fails.
Use the backend client and app subject from Installation. Each operation below is a separate action.
Set BEACON_EVENT_ID to the source event to remove. Its tombstone prevents a retry from restoring the evidence.
import { beacon, subject, required } from './client.mjs';
const receipt = await beacon.retract(subject, required('BEACON_EVENT_ID'));
console.log(JSON.stringify(receipt, null, 2));Set BEACON_GRANT_ID to the app grant to withdraw. Revocation erases its source events and survives restart.
import { beacon, subject, required } from './client.mjs';
const receipt = await beacon.revoke(subject, required('BEACON_GRANT_ID'));
console.log(JSON.stringify(receipt, null, 2));The matcher includes Samsung Digital City in Suwon and Stanford’s main campus. An IP point yields area candidates. A permissioned device estimate can yield a location match when its reported accuracy circle plus a 25 m guard fits inside the mapped perimeter.
Optional browser permission. Coordinates are processed on this device and are not uploaded or saved.
Sourced public points, synthetic visits. The 250 m proximity window is a configurable search area, not measured accuracy or proof of affiliation.
Coordinate sourceIP accuracy is unknown here. Finer provider coordinates are used internally for candidate matching; public coordinates and weather cache cells remain coarse. Stale, denied and missing-accuracy readings stay unavailable. Boundary overlaps remain candidates.
Browser Geolocation requires an explicit user action and permission. The demo processes coordinates locally without uploading or retaining them. A campus estimate does not establish employment or enrollment. The community-mapped perimeters are not surveyed boundaries.
Network registration is separate: AS32 maps to Stanford University and AS6619 to Samsung SDS, including possible customer or remote traffic. These signals do not establish a person’s affiliation.
Use a backend bearer key for every /v1 request. The key determines the app. POST bodies must be JSON and at most 64 KiB. The adapter requires HTTPS outside loopback and has a five-second timeout. /api/context is the website’s separate, unauthenticated environment endpoint.
/api/contextAvailable request observations; enrichment is optional
enrich/v1/taxonomyFind up to 20 eligible categories
q/v1/eventsAdmit structured interest evidence
JSON body: AgentInterestEvent
/v1/profileRead a purpose-scoped interest profile
subjectpurpose/v1/retractRetract an event and retain its replay tombstone
JSON body: subject, eventId
/v1/revokeRevoke a grant and erase its source events
JSON body: subject, grantId
| Field | Type / values |
|---|---|
schemaVersion | 1 |
id | string |
grantId | string |
appSubjectId | string |
conversationId | string |
topicId | string |
kind | AgentInterestKind |
origin | user_statement | user_action | ad_response | agent_text |
about | user | other | hypothetical |
confidence | number |
observedAtMs | integer |
expiresAtMs | integer |
evidenceRef | string |
Gateway success responses use HTTP 200. Errors contain an error string: 400 for invalid input or a domain rejection, 401 for an invalid key, 404 for an unknown route, 413 for an oversized body, 415 for a non-JSON POST, and 429 at local capacity. Queue transient retries with the same event ID; invalid grants require correction.
The local engine is single-writer and acknowledges atomic private-file replacement. Its limit is 100,000 events plus tombstones. Abrupt termination can require stale-lock recovery after confirming the writer is gone. Production provisioning, retention compaction, extraction evaluation and paid delivery remain implementation work.