<OxyAppProvider> — the provider resolves
the app’s identity and shares a credentialed fetcher. Hooks fail loudly if called
outside it.
Reading data
useQuery
Run inline SQL against the project’s warehouse and get typed rows back.
SELECT / WITH only, capped at 10,000 rows.
paramsfill the SQL’s{{ params.X | sqlquote }}placeholders. They are sent alongside the SQL and substituted by the server, which writes a string as a literal the query’s database reads as that value. The escaping differs by engine — a backslash is an ordinary character to DuckDB and Postgres and an escape to ClickHouse, MySQL, Snowflake, Redshift and BigQuery — and only the server knows which engine the database is. A number or boolean is written as itself, and a missing ornullparam asNULL.{{ params.X }}with no filter is written as it is, unquoted. Use it for a number, or an identifier you have validated yourself.- Quoting keeps a value a user typed from changing the query. It is not access control: the endpoint runs any read-only SQL a signed-in member sends it.
enabled: falsedefers the request until required inputs (e.g. a user-picked filter) are available.- The query re-runs whenever
sqlor the enabledparamschange.
useSemanticQuery
Query the semantic model by name
instead of writing SQL. The server compiles it through airlayer and executes it
on the same connector path as useQuery, so the result shape matches.
truncated is true when the result hit the server row cap. Pass
{ debug: true } as the second argument to also get the compiled sql back
while developing.
Running agents
useAgentRun
Start an analytics agent run and stream its events over
SSE. Use this when you want to build your own chat or results UI.
state is needs_clarification, call ask() again to answer and resume.
useProcedureRun
Start a long-running automation, poll its progress,
and cancel it. Runs survive server restarts.
Rendering components
<OxyChat>
A drop-in chat UI over useAgentRun — the fastest way to embed conversational
analytics in your app.
<OxyAnswer>
Renders an agent answer: markdown plus SQL artifacts and a link back to the full
thread. Link URL schemes are allowlisted (it rejects javascript: and similar),
so it’s safe to render model output.
Viewer identity and sign-out
@oxy-hq/sdk/shell exposes who is viewing the app and a way to end their
session:
useIdentity()returns{ id, name, email, picture, kind, reach, loading }.kindis"member"or"frontline";emailisnullfor a frontline worker.reach({ everywhere, via, locations }) is for display only — a greeting, a default store — never for authorization; gate onctx.user.reachinside a function.signOut(fetcher, loginUrl?)ends the platform session and sends the viewer to the login page with the app as the place to return to. It throws if the server refuses, so the app never navigates away from a session that still exists.
@oxy-hq/sdk/ops turns ctx.user.reach into checks:
requireReach(ctx, locationId) returns a 403 response (or null to proceed),
predicate(reach, column, params) returns a SQL condition limiting rows to the
caller’s locations, and isAdmin(ctx) / adminOnly(what) gate app-admin
actions.
Errors
OxyApiError is the structured { message, code? } envelope the server returns.
Hook error values are normal Error objects you can render directly; check for
OxyApiError when you want to branch on code.
Metric-tree analyses
For programmatic access to the metric tree and anomaly inbox, the package root also exportsMetricTreeClient and
AnomaliesClient (plus their result types — ExplainResult,
SensitivityResult, OpportunityResult, Anomaly, and more). These call the
same endpoints the World Model graph uses, so you can build custom
root-cause and sensitivity views.
Scenario forecasting
Three hooks —useBaseline, usePredict and useProjection — cover the
what-if canvas, split by what each one costs:
Fetch the two query-backed ones when the window changes;
usePredict
touches no database and is meant to re-run as the analyst drags a lever. It is
also why the split exists: usePredict cannot measure a coefficient itself, so
feed it useBaseline’s values and fitted — without them, a driver edge
whose .view.yml declares no coefficient: propagates nothing and its
downstream measures are simply absent from impacts.
useProjection returns the baseline curve only. The scenario’s second curve
is arithmetic over that curve and the usePredict result, composed on the
client so a lever edit never costs a query. A series carrying a refusal —
most often too little history to fit — is a stated absence, never a flat
forward line.
Next steps
Oxygen Functions
Run server-side handlers with
useFunctionThe semantic model
Define the measures
useSemanticQuery reads