Concepts & Strategy7 min read

Serving One Product Catalogue to Web, Mobile, Signage and Kiosk

A retailer ships a new product line on Friday.

Published September 10, 2026

A retailer ships a new product line on Friday. The website updates instantly, but the in-store kiosk still shows last season's price, the mobile app truncates the spec table into unreadable mush, and the digital signage above the checkout is running a hardcoded PNG someone exported three campaigns ago. Now four teams are patching four copies of the same catalogue, and the only thing they agree on is that none of them match.

This is the predictable failure of treating each channel as its own project. When the catalogue lives inside the website's rendering logic, every new surface (mobile, signage, kiosk, voice, an in-car display) becomes a fresh integration and a fresh place for the truth to drift. The stakes are wrong prices at the point of sale and a brand that contradicts itself in public.

This article reframes the problem: stop authoring pages and start modeling the product once as structured, presentation-free content, then let each channel query the shape it needs. That single decision, not more integrations, is what makes one catalogue serve web, mobile, signage, and kiosk without divergence.

Why does one catalogue drift into four different catalogues?

One catalogue drifts into four because most systems store content coupled to a single channel's rendering, so every new surface forks the data instead of reading it. The classic version: your catalogue lives as pages in a website CMS, with prices, descriptions, and images arranged for a specific web template. The mobile team can't reuse that, so they build an export. Signage needs a landscape hero and a price, so someone maintains a spreadsheet. The kiosk vendor asks for a feed, so an engineer writes a nightly job. Four consumers, four representations, four update paths.

The drift is not a discipline problem you can solve with more process. It is structural. When the canonical price sits inside a page's markup, there is no single field to change; there are four fields in four systems, and they fall out of sync the first time a deadline compresses. Batch exports make it worse by baking in latency, so the kiosk is always a few hours behind reality, which is exactly the surface where a wrong price costs a real sale.

The reframe is to separate what a product IS from how any one channel shows it. A product has a name, a set of variants, a price, a spec table, and a gallery. Those facts are channel-neutral. The web layout, the signage crop, and the kiosk's touch targets are presentation, and presentation belongs at the edge, computed per channel from one source. Get that boundary right and the four catalogues collapse back into one, because there was only ever one product; the other three were copies pretending to be originals.

What does 'model once, present anywhere' actually mean?

Model once, present anywhere means you define the product as structured data with typed fields and relationships, then each channel queries that data and renders it in its own idiom. The model is the contract. A product document holds a title, a reference to a brand, an array of variants (each with a SKU, price, and inventory reference), a structured spec table, and a gallery of assets. Nothing in that document knows what a web page or a kiosk looks like, and that is the point.

This is the first Sanity pillar, model your business, put to work. In Sanity you express the catalogue as portable schemas with `defineType`, so a variant is a real typed object rather than a blob of HTML. Rich descriptions are stored as Portable Text, a structured rich-text format rather than a string of markup, which means the same paragraph can render as styled HTML on web, as plain attributed text on a kiosk with a different design system, and as clean, readable input for an AI assistant summarizing the product. TypeGen then turns those schemas into TypeScript types, so every consuming app gets compile-time safety against the same shape.

Contrast this with authoring pages. A page-based tool asks you to place a price into a layout; a model-based approach asks you to record that a variant costs a given amount, full stop. The web app decides to show it in a pricing card, the signage app decides to show it 400 pixels tall, and the kiosk decides to show it next to an add-to-basket button. Because the fact lives in one field, changing it once changes it everywhere the next time each channel queries, with no export, no reconciliation, and no fork.

How do four different channels each get exactly the shape they need?

Each channel gets exactly the shape it needs by querying the same content store with a projection that returns only the fields that channel renders, in the structure it expects. This is where a query language earns its keep. With GROQ, a channel asks for the precise shape it needs in one round trip, including projections, references, and filters, so there is no over-fetching and no client-side reshaping.

A web product page might project the full document: title, the entire spec table, the gallery, related products resolved through a reference with the `->` operator, and every variant. Digital signage wants almost none of that. Its query projects title, one hero image, and the lead price, and nothing else crosses the wire, which matters when the display is a low-powered media player on a store network. The kiosk sits in between: it needs variants and live inventory for the specific store, so its query filters variants by availability and resolves the inventory reference for that location. The mobile app wants the same facts as web but a lighter gallery and a flattened spec table sized for a small screen.

Four queries, one document. Crucially, the shaping happens at read time against the canonical data, not by maintaining four stored copies. When a merchandiser corrects a spec, the correction lands in one field, and the next signage query, the next kiosk query, and the next web request all read the corrected value. GROQ also blends filtering and scoring, so a kiosk's 'similar products' rail and the web page's recommendations can be different queries over the same graph rather than two separately curated lists that quietly diverge.

How do you keep a kiosk and signage in sync without stale nightly feeds?

You keep a kiosk and signage in sync by driving them from live queries and change events instead of scheduled batch exports, so a published edit reaches the screen in seconds rather than on tomorrow's cron. Nightly feeds are the hidden cause of most point-of-sale price mismatches: the moment you introduce a batch window, you guarantee that for some hours the physical store is showing a number the website has already corrected.

The Content Lake is a real-time, schema-aware content store, which means channels can subscribe to changes rather than poll a stale export. The Live Content API pushes updates to connected surfaces, so a kiosk holding an open session can reflect an inventory change without a full reload, and signage can rotate to updated pricing the moment a Content Release goes live. Because the store is queryable in real time, the kiosk's 'in stock at this location' badge reads current data instead of last night's snapshot.

Governance is the other half of staying in sync. Content Releases and Scheduling let a merchandising team stage a coordinated price change across the whole catalogue and publish it at a single moment, so web, mobile, signage, and kiosk all flip together rather than trickling out of alignment as separate deploys land. Roles & Permissions decide who can push that release, and Audit logs record who changed what and when, which is the difference between a controlled Friday launch and a frantic Friday afternoon of everyone editing live. The screen on the wall is only as trustworthy as the workflow behind it, and a governed release beats a race condition every time.

Where does presentation logic actually belong across web, mobile, signage, and kiosk?

Presentation logic belongs at the edge, inside each channel's own frontend, computed from the shared model rather than stored in it. The catalogue should never contain a 'signage hero crop' field or a 'kiosk button label' baked into the product; those are decisions the signage app and the kiosk app make from channel-neutral facts. Keep presentation out of the model and you keep the model reusable; leak presentation in and you have quietly rebuilt the four-catalogue problem inside one database.

In practice this means the web app owns its React components and layout, the mobile app owns its native or React Native views, and each renders the projected data through its own design system. Portable Text is what makes rich content survive this split: because a description is structured, the web renderer maps a callout block to a styled component, the kiosk maps the same block to its touch-friendly design system, and neither hardcodes HTML that the other has to strip. The design-system mapping lives in the channel, exactly where it should.

Sanity's own surfaces respect this boundary too. Sanity Studio is a customizable React editor you ship, so editors get product-specific inputs (a variant matrix, an asset picker) without those authoring conveniences leaking into the stored data. The Presentation Tool and Visual Editing then stitch the editor to a live preview of any given channel, so a merchandiser can see how a change looks on the web page without the web page's layout becoming part of the catalogue. Editors get the visual context they expect; the model stays presentation-free; each channel keeps full control of how the same product looks on its own screen.

What breaks when you add the fifth channel, and how do you avoid it?

What breaks when you add a fifth channel is the assumption baked into channel-specific storage: if the catalogue was ever shaped for the four screens you had, the fifth (a voice assistant, an in-car display, a partner's marketplace feed, an AI shopping agent) arrives with no representation and triggers another integration project. Avoid it by having modeled the product channel-neutrally from the start, so the fifth channel is just another query, not another fork.

This is the strategic payoff of treating structured content as a shared foundation rather than a set of per-channel silos. When a new surface appears, it does not need a migration or an export pipeline; it needs a projection. A voice assistant queries title, price, and a short Portable Text description it can read aloud. An AI shopping agent queries the whole structured graph and reasons over it, and because descriptions are Portable Text rather than display HTML, the agent reads clean, attributed content instead of scraping markup. A partner feed queries the fields that partner's schema needs, filtered to the products you syndicate.

This is where naming the platform earns its place: Sanity operates as a Content Operating System, the intelligent backend for companies serving one catalogue to many surfaces, because the same modeled content drives publishing, automation, and every channel from one governed store. Legacy tools stop at publishing to the web and treat every other surface as an add-on; a Content Operating System operates content end to end, so the fifth channel scales output rather than headcount. Functions and the App SDK extend this further, running serverless automation (translation, enrichment, moderation) against the catalogue so a new locale or a new marketplace is content work, not a rebuild.

Serving one catalogue to many channels: platform capabilities compared

FeatureSanityContentfulStrapiStoryblok
Per-channel query shapingGROQ projects exactly the shape each channel needs in one round trip, with references (`->`), filters, and per-store variant projections.GraphQL or REST returns typed data, but complex per-channel shapes often need multiple queries or client-side reshaping.REST and GraphQL cover reads; deep relational projections typically need populate params or custom controllers.REST and GraphQL deliver content, though nested relations and story trees can require several calls to assemble a shape.
Structured rich text for all surfacesPortable Text stores rich text as structured blocks, so web, kiosk, signage, and AI agents each map blocks to their own renderer.Rich Text is a structured JSON tree renderable per channel, though block customization is more constrained than Portable Text.Rich text ships as blocks or HTML/Markdown depending on config, so portability across custom design systems varies.Richtext renders to HTML or a resolvable schema, workable across channels but less granular for custom block mapping.
Real-time sync to kiosk and signageContent Lake plus the Live Content API push published changes to connected screens in seconds, avoiding stale nightly feeds.Webhooks and the CDA support fast updates; live push to connected surfaces generally means building your own subscription layer.Webhooks and lifecycle hooks trigger rebuilds; continuous live subscriptions to running screens are a custom build.Webhooks plus a real-time visual editor cover previews; live delivery to standalone kiosks is typically app-side polling.
Customizable editor for product inputsSanity Studio is a React app you ship, with custom input components and a variant matrix in `sanity.config.ts` kept out of stored data.The web editor is configurable via app framework and UI extensions, but core authoring UI is largely fixed.The admin panel is customizable and self-hostable, though deep custom inputs mean React plugin work in the admin.The visual editor is a strong preview experience; custom field UIs are more limited than a code-owned editor.
Type safety for every consuming appTypeGen generates TypeScript types from the same schemas, so web, mobile, and kiosk apps compile against one contract.GraphQL codegen produces types from the schema, giving strong typing for GraphQL consumers.Types can be generated for the API, though coverage depends on setup across REST and GraphQL.TypeScript types are available via community and generated tooling, with coverage varying by channel.
Governed coordinated launchContent Releases and Scheduling flip a catalogue-wide price change across all channels at one moment, with Roles & Permissions and Audit logs.Scheduled publishing and releases exist; cross-entry coordinated launches are supported with workflow configuration.Draft and publish plus custom workflows cover staging; coordinated multi-entry releases are largely a custom build.Scheduling and release-style workflows are available, with pipeline features depending on plan tier.

Ready to try Sanity?

See how Sanity can transform your enterprise content operations.