Skills
Skill 37 of 67
Salesforce Commerce Cloud (SFCC / Demandware, SFRA storefront) source techniques: how to get a store’s public data with no Business Manager or OCAPI access — the files and public…
7 minutes · 1,517 words · 8 sections
Install
npx skills add wix/skills --skill rp-source-sfccnpx skills add wix/skills/plugin marketplace add wix/skillsThe first command installs just this skill, by the name in its SKILL.md; the second installs the whole repository.
Technique guide for reading a public SFCC/SFRA storefront. It ships no capture code:
rp-discovery follows its “no adapter exists → capture manually, same output contract”
path, and you write the capture code for each migration as generated project code under
migrations/<project>/src/, with its outputs in migrations/<project>/data/sfcc-discovery/.
⚠️ Nothing site-specific (code, ids, values, fixtures) is ever added to this skill.
/on/demandware.store/Sites-<site>-Site/<locale>/<Controller>. The
homepage og:url often uses one, which gives you the site id and the default locale./on/demandware.static/.... Image renditions:
/dw/image/v2/<REALM>_<ENV>/..../s/<site>/dw/shop/..., /s/-/dw/data/...) answers 401 without credentials.
Don’t ask for Business Manager or OCAPI credentials in this flow; record them as a later
phase. Use sourceMode=public_content.robots.txt. Obey it for every request, and take the sitemap index from it.sitemap_N.xml). These list products, categories and
<image:loc> originals. ⚠️ Sitemaps are incomplete. Pre-order products and variant
SKUs are commonly missing, some listed products aren’t searchable, and some *.html
entries are content assets or malformed. Never treat the sitemap as the catalog.hreflang links. The homepage may have no hreflang, so learn the locale
routes from inner pages before you crawl.| Need | Endpoint / source | Notes |
|---|---|---|
| Category id | Category page markup (cgid) | Links carry it percent-encoded: decode it once, then encode it once when you build a request |
| Category members | Search-ShowAjax?cgid=<id>&start=<n>&sz=<page> | Page until resultCount is reached. Tiles are div.product[data-pid] with the PDP link. A zero-result listing is not a category |
| Full product model | Product-Variation?pid=<id>&quantity=1 → JSON {product} | The main source: sales and list price, variationAttributes with every value, options, availability, min/max order quantity, descriptions, images with alt text, promotions, plus the store’s own custom fields. It is a storefront controller, not a contracted API |
| Variant siblings | Product-Variation?pid=<master>&dwvar_<master>_<attr>=<value> | The master id appears in the value urls. A master alone returns 404. Accept a value only when the response marks that value selected; selectable: false values may not be fetchable |
| Fallback | PDP schema.org JSON-LD (Product, BreadcrumbList) | It holds only the sales price and a flattened availability, so a record built from it lists the missing fields as unobserved |
| SEO and redirect source | PDP/category <title>, meta description, og:*, canonical | Detect template-generated SEO versus SEO set per item. Store paths decoded. A path is a redirect source, never a Wix slug |
The product set is the union of the grid tiles from every category (including categories linked only from the navigation) and the sitemap’s product URLs. Key products by SFCC product id, not by URL: locale renditions have their own canonicals.
inStock, preorder (with inStockDate, which only means a
date when the status is preorder), and out of stock (often no status at all, only a
message). lowStockCount and maxOrderQuantity are hints, never authoritative
quantities.price.list is the compare-at price. promotions[] names promotion ids but
never their rules. callForPrice hides the price and add-to-cart: that needs a human
decision./dw/image/v2/<REALM>_<ENV> and the
query string. Larger sw/sh renditions are upscales.Record the store’s regional facts from the public pages, read-only. Time zone is not exposed
publicly: leave it unknown (not-exposed).
Product-Variation JSON price
(price.sales.currency) or the PDP JSON-LD offers.priceCurrency. Sample products from
every locale route you saw.Sites-<site>-Site/<locale>/, e.g. en_US) and the hreflang links. The language is the
two-letter part (en) and locale is the en-US tag. Other hreflang languages remain adapter
discovery evidence rather than fields in the neutral locale record.paymentCurrency unknown with reason ambiguous, unless the person
names the base one, which is then a supplied value. Never pick one from the default locale
alone.unknown with a reason (not-exposed, unreadable, ambiguous),
never a guess or a default.Build the file with buildSourceRegional (adapter sfcc; evidence names the page or field the
value came from) and write it with writeSourceRegional from lib/source-regional.js to
discovery/source-locale.json. There is no promote step for this public path.
Product and category pages are covered by the capture above. Everything else (about, shipping, returns, FAQ, legal, store locator, forms, gift certificates, loyalty) is usually linked only from the header and footer.
Seeds:
Page-Show pages often appear only there).Rules:
robots.txt, and skip the alternate-locale prefixes.Page-Show?cid=<id> (SFRA content assets), Page Designer pages,
Stores-Find (store locator), and ordinary *.html or extensionless content paths.Product-*, Search-*); and action or AJAX routes (Cart-*, Checkout*,
Account-*, Login-*, Order-*, Wishlist-*, *-Ajax*, form POST targets).
⚠️ Never skip a whole controller family that isn’t on this list. Record it for review
instead.captured, covered-by-catalog, skipped:<reason> or
failed:<status>) in data/sfcc-discovery/page-inventory.json. Re-runs re-attempt
failed.For each captured page, read its content and propose the Wix destination: a static page, CMS items, a form, pickup locations, a gift-card product, or a manual or dropped item. Policy prose such as free-shipping thresholds, delivery times, VAT wording or the return window is evidence for Wix settings, not settings.
data/sfcc-discovery/policy-rules.json, with status: candidate.status: confirmed before
anything is written to Wix.429/503 honoring Retry-After.% must not abort the run.Each stage writes only its own part, through the contracts that already exist:
| Stage (producer) | Writes | Read by |
|---|---|---|
Capture code (migrations/<project>/src/) | Raw data, page-inventory.json, policy-rules.json under data/sfcc-discovery/ | rp-discovery |
rp-discovery | source-schema.json (catalog entities, site_page, confirmed rules as site_policy_rule, gaps in sourceMeta) and the “Gaps” section of source-profile.md, naming each cutover item below | rp-mapper |
rp-mapper | mapping/mapping-plan.json, including each routed entity’s urlPolicy; one mapping/review/mapping-gaps.json row per cutover item | rp-setup-discovery, rp-import-codegen |
rp-setup-discovery | One setup/setup-requirements.json entry per cutover item (automation: manual or blocked, the requirementId below, recommendedAction) | The website handoff (setupContract.manualBlockers) |
| Generated import code | URL state in state/url-preservation/, through lib/url-preservation-state.js (below) | Resume, redirect planning, cutover |
URL state, each file in its own role:
base-paths.json: entity-level route intent from mapping urlPolicy.url-ledger.ndjson: one append-only row per public record (source URL, planned and actual
target).redirects.ndjson: only when both relative URLs are known and differ.unresolved.ndjson: only URLs still waiting on a route decision, a target lookup or
manual review.Cutover items:
requirementId | Trigger | Owner → action | Resolves when |
|---|---|---|---|
sfcc-redirects | Planned redirects.ndjson rows exist | Cutover Operator → enter them in Wix when the domain moves (there is no redirect API) | Each planned old URL lands on its target after cutover |
sfcc-page-build:<path> | A captured page with no automatic destination, or an unresolved.ndjson manual_review page | Cutover Operator → build the page from its captured content, or mark it dropped, before launch | The page is published at its target URL (then its ledger row and redirect follow), or a recorded drop decision exists |
sfcc-policy-unconfirmed:<domain> | A rule still candidate in policy-rules.json | Requires Import Operator → “Confirm or reject the candidate rules in data/sfcc-discovery/policy-rules.json with the merchant, then re-run mapping and setup for site_policy_rule“ | Every rule is confirmed (with the Wix setting read back) or rejected, each with the merchant’s verbatim answer |
sfcc-call-for-price | A product that hides its price | Requires Import Operator → “Ask the merchant how each call-for-price product should sell on Wix, record the answer, and re-import those products” | A recorded answer, and the products read back in that state |
sfcc-option-visibility | Option visibility is unknown | Requires Import Operator → “Confirm which add-on options shoppers can buy, then re-import the affected products” | A recorded answer, and the options read back |
sfcc-partial-variants:<master> | Unresolved variant values | Requires Import Operator → “Re-run the capture to re-attempt them; ask the merchant whether any remaining values are retired” | Every value is resolved or recorded as retired |
sfcc-authenticated-data | Always, on a public-only run | Cutover Operator → tell the merchant that promotion rules, real inventory, customers, orders, gift-certificate balances and offline products need Business Manager access later | A recorded merchant acknowledgement, or the later authenticated pass is complete |
sfcc-alternate-locale:<locale> | Locale renditions seen but not captured | Cutover Operator → tell the merchant that locale isn’t migrated yet | A recorded merchant acknowledgement, or a later locale pass is complete |
⚠️ No cutover UI reads these yet. They are preserved for it, not wired to it.
Salesforce Commerce Cloud (SFCC / Demandware, SFRA storefront) source techniques: how to get a store's public data with no Business Manager or OCAPI access — the files and public storefront endpoints to read, and how to scan the remaining site pages. Use when the source platform is SFCC.
The verbatim description from this skill’s front matter — the string an agent matches on to decide whether to load it.
main, last pushed 8 November 2026.SKILL.md, not by matching a directory convention. 5 distinct layouts observed: skills/*/SKILL.md, skills/wix-headless-replatform/resources/*/SKILL.md, skills/wix-replatform/resources/*/SKILL.md, */SKILL.md, wix-replatform/resources/*/SKILL.md.h1 and no skipped levels:.claude-plugin/marketplace.json by Wix, declaring 1 plugin. It is read for editorial metadata only — never as the skill index, which is always the repository tree./wix/skills.md, and each skill at its own .md URL.