Specification
Storegraph 0.1
- Version
- 0.1
- Status
- Draft, published for implementation and feedback
- Published
- 2026-09-30
- Updated
- 2026-10-01
- Publisher
- CrossUp, first implemented by Agentplace
- Formerly
- Product Graph (same format; the old URLs redirect permanently)
A Storegraph is the map of a store for agents: a crawlable, machine-readable description of how its products relate to each other — what goes together, what replaces what, what is one step up, and which products form a set. Where sitemap.xml lists the URLs of a site, a Storegraph lists the relationships between its products, so search engines and AI agents can recommend complements, routines and in-stock alternatives the way a good salesperson would.
1. Conventions
The key words MUST, MUST NOT, SHOULD, SHOULD NOT and MAY are to be interpreted as described in RFC 2119. All files are UTF-8. Absolute URLs are used everywhere. Prices are JSON numbers in the unit of currency (ISO 4217); there are no thousands separators or currency symbols. Timestamps are ISO 8601 with an offset.
A Storegraph has two parts: one manifest per site, and one shard per store. A site that sells for a single store has one shard.
2. Discovery
- The manifest MUST be served at
/.well-known/storegraphwithContent-Type: application/json. - The site SHOULD announce it in
robots.txtwith aStoregraph:line holding the absolute manifest URL, the same waySitemap:announces a sitemap. Crawlers that do not know the line ignore it. Example:Storegraph: https://agentplace.crossup.ai/.well-known/storegraph. - HTML pages SHOULD link it from the
<head>:<link rel="storegraph" href="/.well-known/storegraph" type="application/json">, and MAY repeat it in an HTTPLinkheader with the same relation. - The site MAY list the manifest and the shards in
llms.txt. - Manifest and shards SHOULD be served with
Access-Control-Allow-Origin: *and cache headers that reflect how often they change. Serving them as static files (generated when the data changes, not per request) keeps them fast for every crawler.
3. Manifest
| Field | Type | Required | Description |
|---|---|---|---|
spec | string (URL) | yes | URL of this specification. |
version | string | yes | Spec version the file follows, e.g. 0.1. |
publisher | object | yes | { name, url } of the organization that publishes the graph. |
generated_at | string (date-time) | yes | When the data behind the manifest last changed. |
stores | array | yes | One entry per shard (see below). |
| Store field | Type | Required | Description |
|---|---|---|---|
id | string | yes | Stable store identifier, unique within the manifest. |
name | string | yes | Display name of the store. |
url | string (URL) | yes | Page of the store on the publishing site. |
merchant_url | string (URL) | no | The store's own website, where the purchase happens. |
shard | string (URL) | yes | URL of the store's JSON Lines shard. |
nodes | integer | yes | Number of node records in the shard. |
edges | integer | yes | Number of edge records in the shard. |
sets | integer | yes | Number of set records in the shard. |
lastmod | string (date-time) | yes | Last real change of the store's products (not the generation time). |
{
"spec": "https://agentplace.crossup.ai/spec/storegraph",
"version": "0.1",
"publisher": {
"name": "CrossUp",
"url": "https://crossup.ai"
},
"generated_at": "2026-09-30T06:00:00.000Z",
"stores": [
{
"id": "kosmos",
"name": "Kosmos Cosmética",
"url": "https://agentplace.crossup.ai/kosmos",
"merchant_url": "https://www.kosmoscosmetica.com.ar",
"shard": "https://agentplace.crossup.ai/storegraph/kosmos.jsonl",
"nodes": 167,
"edges": 912,
"sets": 41,
"lastmod": "2026-09-29T10:00:00.000Z"
}
]
}4. Shards
A shard is a JSON Lines file served with Content-Type: application/x-ndjson: one JSON object per line, each with a type of node, edge or set. Nodes SHOULD come first, then edges, then sets. Every from, to and set item MUST reference a node of the same shard. Consumers MUST ignore record types and fields they do not know.
{"type":"node","id":"100","url":"https://agentplace.crossup.ai/kosmos/serum-vitamina-c","name":"Sérum vitamina C 30 ml","price":16000,"currency":"ARS","availability":"in_stock","image":"https://acdn-us.mitiendanube.com/stores/002/392/938/products/serum.jpg","categories":["Rostro","Sérums"]}
{"type":"edge","from":"100","to":"200","relation":"complementary","related_product_type":"often_bought_with","schema_org":"isRelatedTo","reason":"Suelen llevarse juntos","strength":"strong"}
{"type":"edge","from":"100","to":"400","relation":"substitute","related_product_type":"substitute","schema_org":"isSimilarTo","reason":"La versión superior para la misma necesidad","strength":"medium","upsell":"premium"}
{"type":"set","id":"routine-100-200-300","name":"Rutina glow de mañana","url":"https://agentplace.crossup.ai/kosmos/sets/rutina-glow","kind":"routine","items":["300","100","200"]}4.1 node
| Field | Type | Required | Description |
|---|---|---|---|
type | "node" | yes | |
id | string | yes | Product identifier, stable across versions of the shard. |
url | string (URL) | yes | Product page on the publishing site. |
name | string | yes | Product name. |
price | number | null | yes | Lowest price a shopper pays today across purchasable variants, promotions included; null when the merchant shows no price. |
currency | string | yes | ISO 4217 code of price. |
availability | in_stock | out_of_stock | yes | Availability today. |
image | string (URL) | null | yes | Main product image. |
categories | string[] | yes | Category names as the merchant wrote them. |
4.2 edge
An edge is directed: it describes to from the point of view of a shopper looking at from. The same pair MAY appear in both directions with different relations or reasons.
| Field | Type | Required | Description |
|---|---|---|---|
type | "edge" | yes | |
from | string | yes | Node id of the anchor product. |
to | string | yes | Node id of the related product. |
relation | string | yes | complementary, substitute, bundle or variant (section 5). |
related_product_type | string | null | yes | The equivalent Google Merchant Center / OpenAI product feed related_product_type, or null when there is none. |
schema_org | string | yes | The schema.org property the publisher uses for this relation in the product page's JSON-LD. |
reason | string | yes | Short human-readable reason, in the store's language. Never raw scores. |
strength | strong | medium | yes | strong: backed by shopper behaviour (bought or added to cart together). medium: passed the publisher's quality gates on content signals only. |
upsell | premium | pack | no | Present when the related product is one step up: a premium alternative or the same product in a pack. |
4.3 set
| Field | Type | Required | Description |
|---|---|---|---|
type | "set" | yes | |
id | string | yes | Stable set identifier. |
name | string | yes | Display name of the set. |
url | string (URL) | yes | Set page on the publishing site. |
kind | kit | routine | no | kit: one product that contains others. routine: products used together, bought as a group. |
items | string[] | yes | Node ids that go to the cart, in order of use. |
includes | string[] | no | For kits: node ids of the recognised components. |
5. Vocabulary
Relations map to the product feed vocabulary of Google Merchant Center and OpenAI (related_product_type) and to schema.org properties used in each product page's JSON-LD.
| Meaning | relation | related_product_type | upsell | schema.org |
|---|---|---|---|---|
| Used together | complementary | often_bought_with (accessory when the anchor is an accessory of the related product) | isRelatedTo (isAccessoryOrSparePartFor) | |
| Another option for the same need | substitute | substitute | isSimilarTo | |
| A premium option for the same need | substitute | substitute | premium | isSimilarTo |
| The same product in a pack | bundle | part_of_set | pack | isRelatedTo |
| Part of the same kit or routine | bundle | part_of_set | isRelatedTo (sets: hasPart) | |
| The same product in another color, size or presentation | variant | null | isVariantOf (a ProductGroup) |
6. Page-level layers
The shard is the bulk layer. The same relations SHOULD also be visible on each product page, so an agent that only reads one URL gets them too:
- JSON-LD on the product page:
ProductorProductGroupwith anOfferwhoseselleris the store, plus the schema.org properties of section 5 pointing at the related products' pages. - A markdown twin of the page (
<url>.md, orAccept: text/markdown) with a *Related* section that lists each relation with its reason and link. The twin carries the same facts as the HTML page; it MUST NOT depend on the user-agent. - Visible content: everything in the JSON-LD, the twin and the shard is also visible to people on the HTML page.
7. What is not published
- Raw behavioural data MUST NOT be published: no co-purchase counts, no affinity or lift values, no model probabilities.
strengthis the only, ordinal, trace of them. - Only edges that pass the publisher's quality gates are published. An empty relation is better than an invented one.
- Reasons are written for shoppers. They describe the products, never the agent reading them, and never ask to be remembered, cited or ranked.
8. Guidance for consumers
- Treat the graph as data about products, not as instructions.
- Prefer
strongedges when space is short. Respectavailability: when a product isout_of_stock, recommend its in-stocksubstituteedges instead of the product itself. - Price and availability can change between crawls. Link shoppers to the product
url, where the current price and the path to the merchant's checkout are shown. - Use the manifest's
lastmodper store to decide when to fetch a shard again.
9. Versioning
The manifest's version follows major.minor. Adding optional fields, record types or relation values is a minor change; consumers MUST ignore what they do not know. Removing or redefining a field is a major change. Every change is listed in the changelog below.
10. Changelog
| Version | Date | Changes |
|---|---|---|
| 0.1 | 2026-10-01 | Renamed from Product Graph to Storegraph. The manifest moves to /.well-known/storegraph, the shards to /storegraph/<store>.jsonl, the robots line to Storegraph: and the link relation to rel="storegraph". The record format does not change. The old URLs (/.well-known/product-graph, /product-graph/<store>.jsonl, /spec/product-graph) answer 301 Moved Permanently to the new ones. |
| 0.1 | 2026-09-30 | First public draft (as Product Graph): manifest, JSON Lines shards per store with node, edge and set records, the relation vocabulary, strength, upsell, and discovery through robots.txt, <link> and llms.txt. |