ข้ามไปยังเนื้อหาหลัก

Storefronts and marketplaces

Write the product once, publish it everywhere

The same jacket is one product to you and four different documents to four channels: a shorter title here, a category tree there, an attribute set that only one of them asks for. The mistake is not the retyping — it is that each channel slowly becomes its own version of the truth, and nobody can say which one is right. One record, rendered per channel, fixes that. The part worth building carefully is the refusal: a channel whose required fields are not filled should not be published half-formed.

Triggers
Two
Runs
Hourly
Stack
4 tools
Durable execution
Not required

The flow

The top track keeps one record clean. The bottom track renders it per channel on a timer, and publishes only the channels it can fill completely.

Data

A product record changes

Sheets · Airtable

Orchestration

Normalise the record

n8n · Make

Data

Write the master row

Sheets · Airtable

Orchestration

Every hour

n8n 排程

Orchestration

Render per channel

n8n

Orchestration

Channel fields complete?

n8n IF

Platform

Publish to the channel

Shopify Admin API

Notify

Hold it and say what is missing

Slack · WhatsApp

Step by step

  1. 01

    A product record changes

    Sheets · Airtable

    Somebody edits the master row — a price, a photo, a spec line. This is the only place anyone is allowed to edit. Every channel is downstream of it, and no channel edits back.

  2. 02

    Normalise the record

    n8n · Make

    Trim to a single shape: title, long description, dimensions, materials, images in a fixed order, one category value per channel. Do the shortening and the category mapping here, once, rather than four times inside four branches.

  3. 03

    Write the master row

    Sheets · Airtable

    Store the normalised record next to what each channel currently holds. The gap between those two columns is the whole job — without it you cannot tell an unpublished edit from a channel that quietly rejected one.

  4. 04

    Every hour

    n8n 排程

    The publishing pass runs on a timer rather than on the edit. Editing is bursty — somebody fixes eleven rows in four minutes — and a timer collapses that into one pass per channel instead of eleven.

  5. 05

    Render per channel

    n8n

    Build one payload per channel from the master row: its own title length, its own category id, its own attribute names. The record does not change between channels. Only the rendering does.

  6. 06

    Channel fields complete?

    n8n IF

    Check the payload against what that channel requires before you send it. This is where a missing attribute is cheap; after the call it is a rejected listing, or worse, a published one with a blank where the size should be.

  7. 07

    Publish to the channel

    Shopify Admin API

    Send the full record, not a patch. Sending the whole thing is what makes the master row authoritative — but it also means an incomplete payload erases what it omitted, which is why the check sits in front of this step and not after it.

  8. 08

    Hold it and say what is missing

    Slack · WhatsApp

    Name the product, the channel, and the exact field. A message that says only "listing failed" sends someone into the seller centre to find out which of forty attributes it was, which is the work you were removing.

What the platform will not allow

Publishing a whole record is not a stylistic choice. It is what the write actually does, and the consequences are documented.

  • productSet "performs multiple operations to create or update products in a single request", and for list fields — variants, collections, metafields — it "Creates new entries, updates existing ones, and deletes omitted entries". A payload rendered from a partial record does not skip what it left out. It deletes it.

    Shopify Admin GraphQL API — productSet
  • The same mutation runs synchronously by default and returns the updated product; pass synchronous: false and you get a ProductSetOperation instead, whose status you have to poll. Shopify also notes that "By default, stores have a limit of 2048 product variants for each product" — a ceiling worth knowing before a size-by-colour matrix is generated rather than typed.

    Shopify Admin GraphQL API — productSet
  • For a catalogue-sized push, bulk import takes a staged JSONL file capped at 100MB, one input per line. From API version 2026-01 "each app can run up to five bulk mutation operations per shop simultaneously"; on earlier versions it was one at a time per type. Result files are authenticated and expire after one week, so a run nobody read is a run that has to happen again.

    Shopify — Bulk import data with GraphQL
  • If the master record lives in Airtable, the read side is metered too: "The API is limited to 5 requests per second per base", with 50 per second across a token, and exceeding it returns 429 and "you will need to wait 30 seconds before subsequent requests will succeed". An hourly pass that reads row by row hits this long before the storefront notices anything.

    Airtable Web API — Rate limits

When this is not worth building

Three cases where the upkeep costs more than the retyping.

  • You hold a few dozen products that change once a season. Rendering them by hand four times a year is less work than owning a mapping table that has to be corrected every time a channel renames a category.

  • The channels genuinely want different products. If one carries a bundle and another carries the single unit, they are not the same record rendered differently — forcing them into one row creates a translation layer nobody can read.

  • Nobody has agreed which system is the master. Until that is settled, the flow does not remove disagreement about the catalogue; it publishes one side of it on a timer, and the other side keeps editing underneath.

Related reading

ติดต่อเรา

กระบวนการไหนที่คุณควรทำจริง ๆ

เรารันกระบวนการเหล่านี้ให้ทีมปฏิบัติการในฮ่องกงทุกสัปดาห์ บอกเราว่าขั้นตอนไหนกินเวลาคุณ แล้วเราจะบอกว่าทำอัตโนมัติแล้วคุ้มหรือไม่

เริ่มพูดคุย