Price Details
Everything about one item's price before buying, with a deal verdict, price history, the delivered cost and other sellers' offers.
Experience · Shares patterns with Chart, Comparison Matrix, KPI Card
≈ 2,792 tokens per use (tool 1,260 · guidance 340 · typical payload 1,192)How token costs are estimated
Example: Price Details
Is this a good price for the Northwind X2 laptop?

Northwind X2 laptop (opens in a new tab)
Graphite · 16 GB · 512 GB
Members $929
Good price: Only a one-day August sale was lower.
Price history
Lowest $899 on Aug 12 · Highest $1,099 on Sep 19 · Now $949 ($50 above the low)
| Date | Price |
|---|---|
| Jul 11 | $1,099.00 |
| Jul 12 | $1,099.00 |
| Jul 13 | $1,099.00 |
| Jul 14 | $1,099.00 |
| Jul 15 | $1,099.00 |
| Jul 16 | $1,099.00 |
| Jul 17 | $1,099.00 |
| Jul 18 | $1,099.00 |
| Jul 19 | $1,099.00 |
| Jul 20 | $1,099.00 |
| Jul 21 | $1,099.00 |
| Jul 22 | $1,099.00 |
| Jul 23 | $1,099.00 |
| Jul 24 | $1,099.00 |
| Jul 25 | $1,099.00 |
| Jul 26 | $1,099.00 |
| Jul 27 | $1,099.00 |
| Jul 28 | $1,099.00 |
| Jul 29 | $1,099.00 |
| Jul 30 | $1,099.00 |
| Jul 31 | $1,099.00 |
| Aug 1 | $1,099.00 |
| Aug 2 | $1,099.00 |
| Aug 3 | $1,099.00 |
| Aug 4 | $1,099.00 |
| Aug 5 | $1,099.00 |
| Aug 6 | $1,099.00 |
| Aug 7 | $1,099.00 |
| Aug 8 | $1,099.00 |
| Aug 9 | $1,099.00 |
| Aug 10 | $999.00 |
| Aug 11 | $999.00 |
| Aug 12 | $899.00 |
| Aug 13 | $999.00 |
| Aug 14 | $999.00 |
| Aug 15 | $1,099.00 |
| Aug 16 | $1,099.00 |
| Aug 17 | $1,099.00 |
| Aug 18 | $1,099.00 |
| Aug 19 | $1,099.00 |
| Aug 20 | $1,099.00 |
| Aug 21 | $1,099.00 |
| Aug 22 | $1,099.00 |
| Aug 23 | $1,099.00 |
| Aug 24 | $1,099.00 |
| Aug 25 | $1,099.00 |
| Aug 26 | $1,099.00 |
| Aug 27 | $1,099.00 |
| Aug 28 | $1,099.00 |
| Aug 29 | $1,099.00 |
| Aug 30 | $1,099.00 |
| Aug 31 | $1,099.00 |
| Sep 1 | $1,099.00 |
| Sep 2 | $1,099.00 |
| Sep 3 | $1,099.00 |
| Sep 4 | $1,099.00 |
| Sep 5 | $1,099.00 |
| Sep 6 | $1,099.00 |
| Sep 7 | $1,099.00 |
| Sep 8 | $1,099.00 |
| Sep 9 | $1,099.00 |
| Sep 10 | $1,099.00 |
| Sep 11 | $1,099.00 |
| Sep 12 | $1,099.00 |
| Sep 13 | $1,099.00 |
| Sep 14 | $1,099.00 |
| Sep 15 | $1,099.00 |
| Sep 16 | $1,099.00 |
| Sep 17 | $1,099.00 |
| Sep 18 | $1,099.00 |
| Sep 19 | $1,099.00 |
| Sep 20 | $999.00 |
| Sep 21 | $999.00 |
| Sep 22 | $999.00 |
| Sep 23 | $999.00 |
| Sep 24 | $999.00 |
| Sep 25 | $999.00 |
| Sep 26 | $999.00 |
| Sep 27 | $999.00 |
| Sep 28 | $999.00 |
| Sep 29 | $999.00 |
| Sep 30 | $999.00 |
| Oct 1 | $999.00 |
| Oct 2 | $949.00 |
| Oct 3 | $949.00 |
| Oct 4 | $949.00 |
| Oct 5 | $949.00 |
| Oct 6 | $949.00 |
| Oct 7 | $949.00 |
| Oct 8 | $949.00 |
Other offers
- $808.99View Refurb Depot's offer (opens in a new tab)Refurb DepotLowest total
Refurbished · +$9.99 shipping · Arrives Tue, Oct 13. Price $799.00. Rated 4.3 out of 5
- $949.00View Bayside Electronics's offer (opens in a new tab)Bayside Electronics
New, Free shipping · Arrives Thu, Oct 15. Price $949.00. Rated 4.7 out of 5
- $958.99View Cobalt Computers's offer (opens in a new tab)Cobalt Computers
New, +$19.99 shipping · Arrives Mon, Oct 12. Price $939.00. Rated 4.5 out of 5
When to use
- The user asks about one item's price: is this a good price, what will it cost delivered, where is it cheapest, has it dropped.
- A store, price tracker or checkout quote returned the prices, and optionally the history, a cost breakdown or other sellers' offers.
When not to use
- The agent doesn't have prices from a tool. Never invent, estimate or recall prices.
- The user is choosing between different products. Use a Comparison Matrix.
- The user still has to pick a size or color. Use Product Options.
- The user is reviewing several items before checkout. Use a Cart.
How the agent should use it
- Copy every price, row, point and offer from the tool result unchanged, in one currency. Don't round or fix totals: the component flags totals that don't add up.
- Only set
dealwhen the history or offers support it, and ground the reason in them, e.g. "Lowest price in 90 days". The verdict is shown as an icon and words, never as color alone. - End
historywith today's price, as daily or weekly points. - Keep
memberPrice.labelgeneric ("Members"), never a program's brand name. - On
watch-price, set up the alert for the target; onadd-to-cart, use the host's cart. Never buy in chat. - Lifecycle: prices are live data, so set
fetchedAtandstaleAfterMs(e.g. 1 hour) on the call, and the Renderer shows the card as stale once that passes. When the price is a time-limited deal (a flash sale, a held quote), setexpiresAttoo. Use supersede when the agent re-checks the same item.
What it shows
One large number leads: the current price, or the total when there's a cost breakdown. Sections follow, separated by space; their names are read to screen readers only.
| Section | Shown when | Notes |
|---|---|---|
| Header | Always | Thumbnail (only when item.image is set), name and variant |
| Price | Always | The current price, the was price struck through with "Save $150 (14%)", and one quiet line with the member price and unit price ("Members $929 · $0.42 / 100 g") |
| Deal verdict | deal | "Good price · Only a one-day August sale was lower", with a thumbs-up, minus or trending-up icon. Keep reason short |
| Cost breakdown | breakdown | The total moves to the top as the large number ("Delivered total" when there's a shipping row). Below it, the rows: base, discounts and credits as negatives, taxes, shipping ("Free" at 0), fees and deposits. Row notes are read to screen readers only |
| Price history | history | A step line with the latest point marked and pills on the lowest and highest prices. Range tabs (30d, 90d, 1y) only when the history spans more than 90 days. A summary ("Lowest $899 on Aug 12 · Highest $1,099 on Sep 19 · Now $949") is read to screen readers |
| Other offers | offers | Sorted by delivered total (price + shipping, or the stated total). The cheapest is marked "Lowest total" with an icon. Each row shows the seller, one quiet line (condition when not new, shipping, delivery) and the delivered total. Rating and item price are read to screen readers |
Totals that don't add up
The breakdown is reconciled in integer minor units, within 0.01: discounts and credits subtract (whichever sign the source used), every other kind adds. When total differs from the rows, the card shows the stated total with a warning under the rows, such as "Totals don't add up: the rows come to €497.79, but the total is €500.00." Without total, the rows' sum is shown as the total.
Actions
Actions come from the closed set watch-price, add-to-cart and open-offer. Omit actions for a read-only card. The first footer action is the primary button.
- Watch price opens an inline field: "Tell me when it drops below". The target must be a positive amount below the current price, and the field says so if it isn't. It returns
{ action: "watch-price", target: 900 }, and the footer shows "Watching for under $900". - Add to cart is a handoff: it returns
{ action: "add-to-cart" }and your app adds the item with its own cart. open-offeradds a View link to each offer (http(s) URLs only, opened in a new tab). The first click on each seller returns{ action: "open-offer", seller: "Refurb Depot" }.
Each action locks after use, and the others stay available. Each calls onResult once (once per seller for offers).
Installation
npx shadcn@latest add https://your-site.com/r/price-details.json
Usage
import { tool } from "ai"
import { priceDetailsTool } from "@/components/genui/price-details.schema"
const tools = {
// No execute: the user's first action is the tool result.
[priceDetailsTool.name]: tool({
description: priceDetailsTool.description,
inputSchema: priceDetailsTool.inputSchema,
}),
}Render the tool call and handle each action:
import { PriceDetails } from "@/components/genui/price-details"
function ToolPart({ part, addToolResult }) {
if (part.type !== "tool-show_price_details") return null
return (
<PriceDetails
{...part.input}
status={part.state === "input-streaming" ? "streaming" : undefined}
result={part.state === "output-available" ? part.output : undefined}
onResult={(result) => {
if (result.action === "add-to-cart") addToCart(part.input.item)
if (part.state !== "output-available") {
addToolResult({ tool: "show_price_details", toolCallId: part.toolCallId, output: result })
} else {
// Later actions: send them as a follow-up so the agent can act.
sendMessage({ text: `Price action: ${JSON.stringify(result)}` })
}
}}
/>
)
}The agent receives one of:
{ action: "watch-price", target: 900 }
{ action: "add-to-cart" }
{ action: "open-offer", seller: "Refurb Depot" }With LangGraph
Push it from a graph node with ui.push({ name: "show_price_details", props: { toolCallId, ...args } }, { message }), and render the thread's UI messages with the Renderer.
Restoring from history
When a conversation is reloaded, pass the stored result back as result, or an array of results when several actions were taken. Those actions show as done ("Watching for under $900") and stay locked; they never call onResult again.
<PriceDetails
{...part.input}
result={part.state === "output-available" ? part.output : undefined}
/>Accessibility
The chart's SVG is hidden from screen readers; a visually hidden table lists every point in the visible range, and a visually hidden summary states the low, the high and where today's price sits. Range tabs are buttons with aria-pressed. Struck-through and negative amounts are read as "was" and "minus". The watch field is labelled, and an invalid target is announced.
Schema
| Prop | Type | Notes |
|---|---|---|
item | { name, variant?, image?: { src, alt }, url? } | src http(s) or data:image; url http(s). Data-bound |
currency | string | ISO 4217 code for every amount |
price | { current, was?, unit?: { amount, per }, memberPrice?: { amount, label } } | Data-bound |
deal | { verdict: "good" | "fair" | "high", reason }? | One sentence grounded in the history |
breakdown | { label, amount, kind, note? }[]? | kind: base, discount, tax, shipping, fee, deposit, credit. Up to 12. Data-bound |
total | number? | Checked against the breakdown within 0.01. Data-bound |
history | { date, price }[]? | 2–400 points, ending today. Data-bound |
offers | { seller, price, shipping?, total?, delivery?, condition?, rating?: { score, outOf }, url? }[]? | 2–6 other sellers. condition: new, refurbished, used. rating is read to screen readers only. Data-bound |
asOf | string | When the prices were fetched, ISO 8601. Data-bound |
source | { label, url? } | Where the prices came from. Data-bound |
actions | ("watch-price" | "add-to-cart" | "open-offer")[]? | Omit for a read-only card |
Host props: status (streaming, ready, submitting, done), onResult, result and className.