The useCustomer hook fetches customer profile data and feature access in one request. If the customer does not exist yet, PriceOS will create it automatically.
const result = useCustomer<MyFeatures>(options?)
const result = useCustomer(options?)
Parameters
Enable or disable fetching. Defaults to true.
When true, a 404 is surfaced as an error instead of returning null. Defaults to false.
options.swr
SWRConfiguration<PriceOSCustomer<MyFeatures> | null, Error>
Optional SWR config for caching/revalidation behavior.
Returns
customer
PriceOSCustomer<MyFeatures> | null
Customer data including profile fields and featureAccess.
Whether data is currently loading.
Error from the latest request.
Manually revalidate customer data.
trackUsage
(body) => Promise<TrackUsageResponse>
Tracks usage and revalidates customer and feature-access caches.
checkout
(body) => Promise<CreateCheckoutResponse>
Creates a checkout session and redirects to Stripe Checkout.
openCustomerPortal
(body?) => Promise<CreateCustomerPortalResponse>
Creates a customer portal session and redirects to Stripe Customer Portal.
trackUsage body
Feature key to track usage for (typed to your tracked limit feature keys when using generated types).
Usage amount to record. Defaults to 1.
Stable event key for retries and deduplication.
Unix timestamp in milliseconds for when the event happened.
Optional string key/value metadata attached to the usage event.
When using built-in Next.js handlers (priceos/next), client hook calls must use a positive amount.
For negative adjustments, track usage on your backend with the Node.js SDK or REST API.
Examples
Typed Example
Untyped Example
import { useCustomer } from "priceos/react";
import type { MyFeatures } from "./priceos.types";
export function CustomerCard() {
const { customer, isLoading, error, refetch, trackUsage, checkout, openCustomerPortal } = useCustomer<MyFeatures>();
const customerName = customer?.name ?? "Unknown";
const hasBlogAccess = customer?.featureAccess?.blogs?.hasAccess;
async function onAddSeat() {
await trackUsage({
featureKey: "team_seats",
amount: 1,
eventKey: `add_team_seat_${Date.now()}`,
});
}
async function onUpgrade() {
await checkout({
productKey: "starter_monthly",
successUrl: "https://app.acme.com/settings/billing?checkout=success",
cancelUrl: "https://app.acme.com/settings/billing?checkout=canceled",
});
}
async function onManageBilling() {
await openCustomerPortal();
}
if (isLoading) return <div>Loading...</div>;
if (error) return <button onClick={refetch}>Retry</button>;
return (
<div>
<h3>{customerName}</h3>
<p>Blog access: {hasBlogAccess ? "Yes" : "No"}</p>
<button onClick={onAddSeat}>Add teammate</button>
<button onClick={onUpgrade}>Upgrade</button>
<button onClick={onManageBilling}>Manage billing</button>
</div>
);
}
import { useCustomer } from "priceos/react";
export function CustomerCard() {
const { customer, isLoading, error, refetch, trackUsage, checkout, openCustomerPortal } = useCustomer();
const customerName = customer?.name ?? "Unknown";
const hasBlogAccess = customer?.featureAccess?.blogs?.hasAccess;
async function onAddSeat() {
await trackUsage({
featureKey: "team_seats",
amount: 1,
eventKey: `add_team_seat_${Date.now()}`,
});
}
async function onUpgrade() {
await checkout({
productKey: "starter_monthly",
successUrl: "https://app.acme.com/settings/billing?checkout=success",
cancelUrl: "https://app.acme.com/settings/billing?checkout=canceled",
});
}
async function onManageBilling() {
await openCustomerPortal();
}
if (isLoading) return <div>Loading...</div>;
if (error) return <button onClick={refetch}>Retry</button>;
return (
<div>
<h3>{customerName}</h3>
<p>Blog access: {hasBlogAccess ? "Yes" : "No"}</p>
<button onClick={onAddSeat}>Add teammate</button>
<button onClick={onUpgrade}>Upgrade</button>
<button onClick={onManageBilling}>Manage billing</button>
</div>
);
}