Content Commerce Overview Content commerce bridges editorial content — blog posts, buying guides, lookbooks — with direct product purchasing, capturing high-intent organic traffic and shortening the path from discovery to purchase. Shopify and WooCommerce both have built-in blog functionality where you can link products directly; headless setups require a CMS integration. The key goal is making it easy for your editorial team to embed products without engineering help, and tracking which content pieces actually drive revenue. When to Use This Skill - When a blog drives significant organic tra…

, '£', currency code, or other currency symbol\"\n },\n {\n \"name\": \"Availability uses schema.org URI\",\n \"max_score\": 10,\n \"description\": \"The 'availability' field uses 'https://schema.org/InStock' or 'https://schema.org/OutOfStock' (the full URI, not a short form like 'InStock' alone)\"\n },\n {\n \"name\": \"Output file produced\",\n \"max_score\": 6,\n \"description\": \"A schema_output.json file exists and contains valid JSON with a '@graph' array\"\n }\n ]\n}\n","content_type":"application/json; charset=utf-8","language":"json","size":2668,"content_sha256":"c8d227bb87fe8486cd60c9270bb44ffb164e1b93613033b46ae610c101751f3f"},{"filename":"evals/schema-org-seo-markup-for-shoppable-arti/task.md","content":"# Structured Data for a Product-Rich Buying Guide\n\n## Problem/Feature Description\n\nThe SEO team at a home goods retailer has published a \"Best Ergonomic Office Chairs 2026\" buying guide — a long-form article that recommends five specific chairs, each with pricing and stock status. The team wants Google to show this article as a rich result in search, specifically the kind that surfaces an article alongside a product carousel in Google Search. Without structured data, the page is treated as plain editorial content and misses these high-value placements.\n\nYour task is to write a TypeScript function that generates the correct JSON-LD structured data for this type of article. The data will be injected into the page's `\u003chead>` as a `\u003cscript type=\"application/ld+json\">` block. The structured data must contain all the information Google needs to understand both the article and the products it features.\n\n## Output Specification\n\nWrite a TypeScript file `schema.ts` that exports a function `buildArticleSchema(article, products)` which returns a valid JSON-LD object. Also write a `schema.test.ts` file (or a plain `schema_output.json`) that calls the function with realistic sample data and writes (or logs/exports) the result so the output can be inspected.\n\nUse the following types as your starting point — do not modify them, but you may import or copy them:\n\n```typescript\ninterface Article {\n id: string;\n slug: string;\n title: string;\n body: string;\n featuredProductIds: string[];\n categories: string[];\n publishedAt: Date;\n updatedAt: Date;\n}\n\ninterface Product {\n id: string;\n name: string;\n slug: string;\n images: { url: string }[];\n priceInCents: number;\n inventory: number;\n}\n```\n\nThe STORE_NAME is `\"ErgoHome\"` and the STORE_URL is `\"https://ergohome.example.com\"`. Hardcode these or use them as constants.\n\nProduce a file `schema_output.json` containing the result of calling `buildArticleSchema` with a sample article (slug: `\"best-ergonomic-chairs-2026\"`, title: `\"Best Ergonomic Office Chairs 2026\"`) and at least 3 sample products. Make the sample data realistic.\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":2105,"content_sha256":"08524ec2397706df02f05d1614614e7da5bd603b7d8ea4a81c980e8ec0a37f47"},{"filename":"evals/shoppable-product-embed-component-with-a/criteria.json","content":"{\n \"context\": \"Tests whether the agent builds a ProductEmbed React component that follows content-commerce best practices: render-time data fetching (not static), correct attribution via articleId prop, click tracking to the analytics endpoint, correct product URL format, out-of-stock handling, loading skeleton, and CSS class naming conventions.\",\n \"type\": \"weighted_checklist\",\n \"checklist\": [\n {\n \"name\": \"articleId prop present\",\n \"max_score\": 10,\n \"description\": \"The component accepts an 'articleId' prop (the interface/props type includes 'articleId: string')\"\n },\n {\n \"name\": \"Render-time data fetch\",\n \"max_score\": 12,\n \"description\": \"Product data is fetched inside a useEffect (or equivalent async hook) — NOT hardcoded or passed as a static prop from the server at build/publish time\"\n },\n {\n \"name\": \"Loading skeleton state\",\n \"max_score\": 7,\n \"description\": \"When product data has not loaded, the component renders a loading placeholder (e.g. a div with class 'product-embed-skeleton' or equivalent skeleton element)\"\n },\n {\n \"name\": \"Click tracking endpoint\",\n \"max_score\": 12,\n \"description\": \"On CTA click, a POST request is sent to '/api/analytics/content-click' (exact path)\"\n },\n {\n \"name\": \"Click tracking payload\",\n \"max_score\": 9,\n \"description\": \"The analytics POST body includes all three of: articleId, productId, and ctaText\"\n },\n {\n \"name\": \"Product link includes ref params\",\n \"max_score\": 10,\n \"description\": \"The CTA anchor href includes both 'ref=article' and 'article_id={articleId}' as query parameters in the product URL\"\n },\n {\n \"name\": \"displayStyle CSS class\",\n \"max_score\": 8,\n \"description\": \"The root container element has a CSS class matching the pattern 'product-embed--{displayStyle}' (e.g. 'product-embed--card')\"\n },\n {\n \"name\": \"data-product-id attribute\",\n \"max_score\": 7,\n \"description\": \"The root container element has a 'data-product-id' attribute set to the productId value\"\n },\n {\n \"name\": \"displayStyle options typed\",\n \"max_score\": 7,\n \"description\": \"The displayStyle prop is typed as a union: 'card' | 'inline' | 'full'\"\n },\n {\n \"name\": \"Out-of-stock handling\",\n \"max_score\": 11,\n \"description\": \"When product.inStock is false (or equivalent), the component shows an indicator (e.g. 'Out of stock' text, notify-me button, or alternative products) rather than showing a broken card\"\n },\n {\n \"name\": \"Fetch fields param\",\n \"max_score\": 7,\n \"description\": \"The product fetch URL includes a 'fields' query parameter specifying which fields to retrieve\"\n }\n ]\n}\n","content_type":"application/json; charset=utf-8","language":"json","size":2752,"content_sha256":"50e92ede9774bbf6f92b9d5589d67d946fd71ffcb3b37eec333355d3a6942155"},{"filename":"evals/shoppable-product-embed-component-with-a/task.md","content":"# Shoppable Product Widget for a Lifestyle Blog\n\n## Problem/Feature Description\n\nA direct-to-consumer lifestyle brand runs a content-heavy blog on a Next.js headless frontend, separate from their Shopify storefront. Writers frequently mention specific products in articles — running gear reviews, gift guides, seasonal lookbooks — and the marketing team wants those mentions to become purchasable product cards embedded directly in the article body. Readers should see a product image, name, price, and a call-to-action button without leaving the article.\n\nThe marketing team also needs to understand which specific articles and which specific in-article product placements are driving purchases. This data will feed a monthly content ROI report. Without knowing which embedded product within which article a reader clicked before buying, the team can only attribute revenue to the whole site, not to individual pieces of content.\n\nBuild a React TypeScript component called `ProductEmbed` that can be dropped into an article renderer. The component should handle all the product data fetching, display, and analytics concerns.\n\n## Output Specification\n\nCreate the following files:\n\n- `components/ProductEmbed.tsx` — the React component\n- `components/ProductEmbed.types.ts` — the TypeScript interfaces/types it uses (or inline them in the component file)\n\nThe component must:\n- Accept at minimum `productId`, `displayStyle`, `ctaText`, and one more prop needed for revenue attribution\n- Fetch product data from `/api/products/{productId}?fields=name,price,images,slug,inStock`\n- Show an appropriate loading state while data is being fetched\n- Render the product image, name, price, and a CTA button\n- Handle the case where a product is out of stock\n- Send an analytics event when the CTA is clicked\n\nThe CTA button should navigate to the product page. Include the `articleId` in a way that allows the analytics team to join article clicks to orders.\n\nWrite a short `IMPLEMENTATION_NOTES.md` explaining any attribution decisions you made.\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":2045,"content_sha256":"14a9a3e700bd8d25f55dacab7266e68a981da2323f04496c7f9c4ccbd258cc5e"},{"filename":"evals/utm-content-attribution-and-order-tracki/criteria.json","content":"{\n \"context\": \"Tests whether the agent correctly implements content-commerce UTM attribution: the right UTM parameter names and values for content-driven product links, order attribution storage with all required fields, priority hierarchy for multi-channel attribution, and a SQL query that filters for content source attribution.\",\n \"type\": \"weighted_checklist\",\n \"checklist\": [\n {\n \"name\": \"utm_source = 'content'\",\n \"max_score\": 9,\n \"description\": \"The product URL builder sets utm_source to exactly 'content' (not 'blog', 'article', or another value)\"\n },\n {\n \"name\": \"utm_medium = 'article'\",\n \"max_score\": 9,\n \"description\": \"The product URL builder sets utm_medium to exactly 'article'\"\n },\n {\n \"name\": \"utm_campaign = article slug\",\n \"max_score\": 9,\n \"description\": \"The utm_campaign parameter is set to the article's slug (not the article ID, title, or a category)\"\n },\n {\n \"name\": \"utm_content = product slug\",\n \"max_score\": 10,\n \"description\": \"The utm_content parameter is set to the product's slug (not the product ID, name, or 'product')\"\n },\n {\n \"name\": \"Order attribution fields\",\n \"max_score\": 10,\n \"description\": \"The captureOrderAttribution function stores all four UTM-derived fields: source, medium, campaign, and content (alongside orderId)\"\n },\n {\n \"name\": \"Attribution priority hierarchy\",\n \"max_score\": 10,\n \"description\": \"The code or comments document that paid search takes priority over email, email over content, and content over organic (paid search > email > content > organic)\"\n },\n {\n \"name\": \"SQL WHERE source = 'content'\",\n \"max_score\": 9,\n \"description\": \"The SQL report filters on 'source = content' (or 'utm_source = content') to restrict results to content-driven orders\"\n },\n {\n \"name\": \"SQL includes revenue aggregation\",\n \"max_score\": 8,\n \"description\": \"The SQL query contains a SUM expression for revenue and a COUNT for orders\"\n },\n {\n \"name\": \"SQL groups by article slug\",\n \"max_score\": 8,\n \"description\": \"The SQL query groups results by the campaign column (article slug) and orders/sorts by revenue\"\n },\n {\n \"name\": \"SQL time filter\",\n \"max_score\": 8,\n \"description\": \"The SQL query includes a date filter limiting results to approximately the last 90 days\"\n },\n {\n \"name\": \"URL uses STORE_URL base\",\n \"max_score\": 10,\n \"description\": \"The product URL is constructed with a configurable base URL (environment variable, constant, or parameter) rather than being hardcoded to a specific domain\"\n }\n ]\n}\n","content_type":"application/json; charset=utf-8","language":"json","size":2687,"content_sha256":"be4012617d4a564bc24f8dd7a075205ef1c621d873f91ba69f4afa5561eaaf37"},{"filename":"evals/utm-content-attribution-and-order-tracki/task.md","content":"# Content Revenue Attribution System\n\n## Problem/Feature Description\n\nA mid-size outdoor gear retailer publishes buying guides and gear reviews that attract significant organic search traffic. The head of content wants to prove that the editorial team drives real revenue, not just pageviews. Currently, when a reader clicks a product in a buying guide and later completes a purchase, there is no way to tie that order back to the article that started the journey — all that revenue is lumped into \"direct\" or \"organic\" in the existing analytics dashboards.\n\nThe engineering team needs to build the tracking layer that connects articles to orders. When a reader clicks a product link in an article, specific tracking parameters must be passed along in the URL so that when an order is placed, the attribution can be captured and stored. There is also a complication: the same customer may have come from a Google Ads campaign earlier in the same session, and the team does not want paid search spend to be eclipsed or confused by content attribution — each channel should receive credit according to a defined priority.\n\nYour task is to implement the TypeScript functions that power this attribution pipeline, and to write a SQL query that the data team can use to report on content-driven revenue.\n\n## Output Specification\n\nCreate a file `attribution.ts` containing:\n\n1. A function `buildContentProductUrl(product, article)` that generates a product URL with tracking parameters embedded. The URL should uniquely identify both the article and the specific product placement.\n\n2. A function `captureOrderAttribution(orderId, utmParams)` that stores attribution data for an order (you may use a mock `db` object — just show the call with all necessary fields).\n\n3. A function (or constant/comment) `resolveAttributionSource(touchpoints)` that documents or implements the priority logic for determining which channel gets credit for an order when multiple channels are present in the customer journey.\n\nCreate a file `attribution_report.sql` containing a SQL query that reports content-driven revenue per article over the last 90 days, showing article slug, number of orders, total revenue, and average order value.\n\nWrite a short `ATTRIBUTION_NOTES.md` explaining how the URL parameters connect to the order attribution record.\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":2333,"content_sha256":"45ac5b5d284e20ad0d067138f1ada362212bdf8abc354aa615936fe91255f94a"},{"filename":"tile.json","content":"{\n \"name\": \"finsi/content-commerce\",\n \"version\": \"0.1.0\",\n \"summary\": \"Blog-to-commerce integration, shoppable content, and editorial merchandising\",\n \"skills\": {\n \"content-commerce\": {\n \"path\": \"SKILL.md\"\n }\n }\n}\n","content_type":"application/json; charset=utf-8","language":"json","size":230,"content_sha256":"87c9451cee76225306b00fd76c3cc813e7c1ecf5c03ac51beb867e8794ec90a7"}],"content_json":{"type":"doc","content":[{"type":"heading","attrs":{"level":1},"content":[{"text":"Content Commerce","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Overview","type":"text"}]},{"type":"paragraph","content":[{"text":"Content commerce bridges editorial content — blog posts, buying guides, lookbooks — with direct product purchasing, capturing high-intent organic traffic and shortening the path from discovery to purchase. Shopify and WooCommerce both have built-in blog functionality where you can link products directly; headless setups require a CMS integration. The key goal is making it easy for your editorial team to embed products without engineering help, and tracking which content pieces actually drive revenue.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"When to Use This Skill","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"When a blog drives significant organic traffic but contributes little to revenue","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"When editorial team needs a no-code way to embed products inside articles","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"When implementing SEO-optimized buying guides that rank for \"best [product category]\" queries","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"When building a lookbook or collection page with editorial text and shoppable product grids","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"When needing to track which content pieces drive the most revenue","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Core Instructions","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Step 1: Determine the merchant's platform and content setup","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Platform","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Content Tool","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Shoppable Embedding Approach","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Shopify","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Shopify Blog (built-in)","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Use Shogun or PageFly page builder to embed product cards; or use Shopify's native blog with manual product links","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"WooCommerce","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"WordPress native blog","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Use WooCommerce product blocks (Gutenberg) or WooCommerce Shortcodes to embed products inline","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"BigCommerce","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"BigCommerce Blog or WordPress","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"WordPress: use WooCommerce Shortcodes or a product block plugin; BigCommerce blog: manual product linking only","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Headless / Custom CMS","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Contentful, Sanity, Prismic","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Build a product embed component using the CMS's custom content type system and Storefront API","type":"text"}]}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Step 2: Set up shoppable content","type":"text"}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":4},"content":[{"text":"Shopify","type":"text"}]},{"type":"paragraph","content":[{"text":"Option A: Shopify Blog with native product links (free, simple)","type":"text","marks":[{"type":"strong"}]}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Go to ","type":"text"},{"text":"Shopify Admin → Online Store → Blog Posts","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"In any blog post, highlight text and click the link icon to link to a product page (e.g., ","type":"text"},{"text":"/products/product-handle","type":"text","marks":[{"type":"code_inline"}]},{"text":")","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"To embed a product image with a buy button, use a section or block in your theme:","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Go to ","type":"text"},{"text":"Online Store → Themes → Customize","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"On the blog post template, add a \"Product\" or \"Featured Product\" section and configure it for each post","type":"text"}]}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Limitations: no inline product cards; products appear as separate sections above/below the article body","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"Option B: Shogun or PageFly (recommended for buying guides)","type":"text","marks":[{"type":"strong"}]}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Install ","type":"text"},{"text":"Shogun","type":"text","marks":[{"type":"strong"}]},{"text":" or ","type":"text"},{"text":"PageFly","type":"text","marks":[{"type":"strong"}]},{"text":" from the Shopify App Store","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Create a new landing page for your buying guide or lookbook","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Drag and drop ","type":"text"},{"text":"Product Card","type":"text","marks":[{"type":"strong"}]},{"text":" elements directly into the editorial content","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Each product card shows image, price, and \"Add to Cart\" button with live Shopify inventory","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Publish the page and link to it from your blog or navigation","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"Option C: Instant (previously known as EcomSend) — for in-blog product embeds","type":"text","marks":[{"type":"strong"}]}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Install the Instant page builder app","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Use the blog post editor to add product cards inline within article text","type":"text"}]}]}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":4},"content":[{"text":"WooCommerce","type":"text"}]},{"type":"paragraph","content":[{"text":"Using Gutenberg product blocks (built-in with WooCommerce):","type":"text","marks":[{"type":"strong"}]}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Open any WordPress post in the Gutenberg editor","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Click the + block button and search for \"Products\"","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Insert a ","type":"text"},{"text":"Products (Beta)","type":"text","marks":[{"type":"strong"}]},{"text":" block or ","type":"text"},{"text":"Hand-picked Products","type":"text","marks":[{"type":"strong"}]},{"text":" block","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Search for products by name and select them — a product grid with prices and \"Add to Cart\" appears inline in the article","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"For a single inline product card, use the ","type":"text"},{"text":"Single Product","type":"text","marks":[{"type":"strong"}]},{"text":" block","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"Using WooCommerce Shortcodes (classic editor):","type":"text","marks":[{"type":"strong"}]}]},{"type":"paragraph","content":[{"text":"Insert a product anywhere in article text:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":""},"content":[{"text":"[product id=\"123\"]\n[products ids=\"123,456,789\" columns=\"3\"]\n[product_page id=\"123\"]","type":"text"}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":4},"content":[{"text":"BigCommerce","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"For BigCommerce's built-in blog, you are limited to manual product links — no native product embed blocks","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Recommended","type":"text","marks":[{"type":"strong"}]},{"text":": run WordPress on a subdomain (","type":"text"},{"text":"blog.yourstore.com","type":"text","marks":[{"type":"code_inline"}]},{"text":") with the BigCommerce for WordPress plugin","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"This gives you Gutenberg product blocks (same as WooCommerce setup above) while the main store runs on BigCommerce","type":"text"}]}]}]},{"type":"hr","attrs":{"markup":"---"}},{"type":"heading","attrs":{"level":4},"content":[{"text":"Custom / Headless","type":"text"}]},{"type":"paragraph","content":[{"text":"For headless setups with Contentful, Sanity, or Prismic, build a product embed content type:","type":"text"}]},{"type":"paragraph","content":[{"text":"Sanity schema for a product embed:","type":"text","marks":[{"type":"strong"}]}]},{"type":"code_block","attrs":{"wrap":false,"language":"typescript"},"content":[{"text":"// schemas/productEmbed.ts\nexport const productEmbedType = {\n name: 'productEmbed',\n title: 'Product Embed',\n type: 'object',\n fields: [\n {\n name: 'productId',\n title: 'Product ID',\n type: 'string',\n description: 'Shopify/BigCommerce product ID or handle',\n },\n {\n name: 'displayStyle',\n title: 'Display Style',\n type: 'string',\n options: { list: ['card', 'inline', 'full'] },\n initialValue: 'card',\n },\n {\n name: 'ctaText',\n title: 'CTA Text',\n type: 'string',\n initialValue: 'Shop Now',\n },\n ],\n};","type":"text"}]},{"type":"paragraph","content":[{"text":"React component that fetches live price and inventory from the Storefront API:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"tsx"},"content":[{"text":"export function ProductEmbed({ productId, displayStyle, ctaText, articleSlug }: ProductEmbedProps) {\n const [product, setProduct] = useState\u003cProduct | null>(null);\n\n useEffect(() => {\n fetch(`/api/products/${productId}?fields=name,price,images,slug,inStock`)\n .then(r => r.json())\n .then(setProduct);\n }, [productId]);\n\n if (!product) return \u003cdiv className=\"product-embed-skeleton\" />;\n\n return (\n \u003cdiv className={`product-embed product-embed--${displayStyle}`}>\n \u003cimg src={product.images[0]?.url} alt={product.name} />\n \u003cdiv className=\"product-embed__info\">\n \u003ch3>{product.name}\u003c/h3>\n \u003cp>${(product.priceInCents / 100).toFixed(2)}\u003c/p>\n {!product.inStock && \u003cspan>Out of stock\u003c/span>}\n \u003c/div>\n \u003ca href={`/products/${product.slug}?utm_source=content&utm_campaign=${articleSlug}`}>\n {ctaText}\n \u003c/a>\n \u003c/div>\n );\n}","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Step 3: Add UTM attribution to all content links","type":"text"}]},{"type":"paragraph","content":[{"text":"Append UTM parameters to every product link within content so you can track which articles drive revenue in Google Analytics:","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"For Shopify/WooCommerce native embeds: add ","type":"text"},{"text":"?utm_source=content&utm_medium=blog&utm_campaign=ARTICLE-SLUG","type":"text","marks":[{"type":"code_inline"}]},{"text":" to product URLs manually or via a theme setting","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"For Shogun/PageFly: each button has a URL field — include UTM params there","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"For headless: build UTM parameters into the product embed component automatically using the article slug","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Step 4: Track content-driven revenue","type":"text"}]},{"type":"paragraph","content":[{"text":"In ","type":"text"},{"text":"Google Analytics 4","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Go to ","type":"text"},{"text":"Reports → Acquisition → Traffic Acquisition","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Filter by ","type":"text"},{"text":"Session source = content","type":"text","marks":[{"type":"code_inline"}]},{"text":" to see all orders attributed to blog content","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"For more detail: go to ","type":"text"},{"text":"Explore → Funnel Exploration","type":"text","marks":[{"type":"strong"}]},{"text":" and filter by ","type":"text"},{"text":"utm_medium = blog","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"paragraph","content":[{"text":"In ","type":"text"},{"text":"Shopify Analytics","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Go to ","type":"text"},{"text":"Analytics → Reports → Sales by traffic source","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Filter by source to see UTM-tagged content traffic","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Best Practices","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Fetch product prices live","type":"text","marks":[{"type":"strong"}]},{"text":" — never hardcode prices in CMS content; prices change and stale prices erode trust","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Show \"Out of Stock\" state","type":"text","marks":[{"type":"strong"}]},{"text":" in product embeds — a broken-looking card hurts conversion more than no card at all","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Place product embeds high in the article","type":"text","marks":[{"type":"strong"}]},{"text":" — data shows most readers don't scroll past 60% of an article; embed the first product recommendation within the first 400 words","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Use UTM ","type":"text","marks":[{"type":"strong"}]},{"text":"utm_content","type":"text","marks":[{"type":"code_inline"},{"type":"strong"}]},{"text":" = product slug","type":"text","marks":[{"type":"strong"}]},{"text":" — this lets you see which specific product in an article drove the conversion, not just which article","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Give editorial team a product search tool","type":"text","marks":[{"type":"strong"}]},{"text":" — in Shopify, editors can search products by name when building pages in Shogun/PageFly; do not require them to know product IDs","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Common Pitfalls","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Problem","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Solution","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Product prices in articles are stale","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Always fetch prices from the storefront API at render time; never embed prices as static CMS content","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Out-of-stock products remain embedded in live articles","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Add an inventory check in your product embed component; show \"notify me\" or a related product instead","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"CMS editors can't find products to embed","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Use Shogun/PageFly's product search widget; for headless, build a product picker that queries the Storefront API","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Content attribution double-counts — same order attributed to both content and email","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"In GA4, use last non-direct click as the attribution model, or manually review multi-touch paths in the Path Exploration report","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Buying guide SEO titles not ranking","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Ensure article titles match the exact query format (\"Best [Product Type] for [Use Case] in [Year]\") and include product schema.org markup","type":"text"}]}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Related Skills","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"@social-commerce","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"@influencer-tracking","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"@ecommerce-seo","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"@email-marketing-automation","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"@marketing-attribution-dashboard","type":"text"}]}]}]},{"type":"hr","attrs":{"markup":"---"}}]},"metadata":{"date":"2026-06-05","name":"content-commerce","risk":"safe","tags":["content-commerce","shoppable-content","blog","editorial","seo","product-embedding","cms","headless"],"tools":["claude-code","cursor","gemini-cli","copilot","codex-cli","kiro","opencode"],"author":"@skillopedia","source":{"stars":24,"repo_name":"awesome-ecommerce-skills","origin_url":"https://github.com/finsilabs/awesome-ecommerce-skills/blob/HEAD/skills/marketing-growth/content-commerce/SKILL.md","repo_owner":"finsilabs","body_sha256":"ed0044ba00ec203f4f93cb1e5c062943a0241612656c1011b396e04d61e32a5d","cluster_key":"124289eb8ef74b272969daa0c17446b4ee1b5fb8185c763c2deaaa893f917a69","clean_bundle":{"format":"clean-skill-bundle-v1","source":"finsilabs/awesome-ecommerce-skills/skills/marketing-growth/content-commerce/SKILL.md","attachments":[{"id":"ce2e5c04-a3ca-56e4-a4f2-1c2d31d44857","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/ce2e5c04-a3ca-56e4-a4f2-1c2d31d44857/attachment.json","path":"evals/schema-org-seo-markup-for-shoppable-arti/criteria.json","size":2668,"sha256":"c8d227bb87fe8486cd60c9270bb44ffb164e1b93613033b46ae610c101751f3f","contentType":"application/json; charset=utf-8"},{"id":"96133331-880a-5e55-a8c4-4e26114c5235","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/96133331-880a-5e55-a8c4-4e26114c5235/attachment.md","path":"evals/schema-org-seo-markup-for-shoppable-arti/task.md","size":2105,"sha256":"08524ec2397706df02f05d1614614e7da5bd603b7d8ea4a81c980e8ec0a37f47","contentType":"text/markdown; charset=utf-8"},{"id":"7928ac3e-b1fc-5b21-aaf9-c29ffab321bc","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/7928ac3e-b1fc-5b21-aaf9-c29ffab321bc/attachment.json","path":"evals/shoppable-product-embed-component-with-a/criteria.json","size":2752,"sha256":"50e92ede9774bbf6f92b9d5589d67d946fd71ffcb3b37eec333355d3a6942155","contentType":"application/json; charset=utf-8"},{"id":"9a789757-4080-5e7e-a49e-38b71f294edd","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/9a789757-4080-5e7e-a49e-38b71f294edd/attachment.md","path":"evals/shoppable-product-embed-component-with-a/task.md","size":2045,"sha256":"14a9a3e700bd8d25f55dacab7266e68a981da2323f04496c7f9c4ccbd258cc5e","contentType":"text/markdown; charset=utf-8"},{"id":"66f6fb69-b17b-5215-87b0-74f21770424a","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/66f6fb69-b17b-5215-87b0-74f21770424a/attachment.json","path":"evals/utm-content-attribution-and-order-tracki/criteria.json","size":2687,"sha256":"be4012617d4a564bc24f8dd7a075205ef1c621d873f91ba69f4afa5561eaaf37","contentType":"application/json; charset=utf-8"},{"id":"ee127738-fb5a-5697-8ba2-9c3aeb9e1c39","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/ee127738-fb5a-5697-8ba2-9c3aeb9e1c39/attachment.md","path":"evals/utm-content-attribution-and-order-tracki/task.md","size":2333,"sha256":"45ac5b5d284e20ad0d067138f1ada362212bdf8abc354aa615936fe91255f94a","contentType":"text/markdown; charset=utf-8"},{"id":"016e0909-e2bd-5ca9-aaca-dd979e1ecc04","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/016e0909-e2bd-5ca9-aaca-dd979e1ecc04/attachment.json","path":"tile.json","size":230,"sha256":"87c9451cee76225306b00fd76c3cc813e7c1ecf5c03ac51beb867e8794ec90a7","contentType":"application/json; charset=utf-8"}],"bundle_sha256":"079fbf8121fb5193b158eaf6d77e259b3f5011a289999d57bb5866e445b010b4","attachment_count":7,"text_attachments":7,"attachment_storage":"skillopedia-attachments-v1","binary_attachments":0,"excluded_attachments":[]},"cluster_size":1,"skill_md_path":"skills/marketing-growth/content-commerce/SKILL.md","import_metadata":{"date":"2026-06-05","author":"@skillopedia","version":"v1","category":"browser-automation-scraping","category_label":"Browser"},"exact_dupes_collapsed_into_this":0},"version":"v1","category":"browser-automation-scraping","triggers":["content commerce","shoppable blog","shoppable content","editorial merchandising","blog to commerce","product embedding in blog"],"platforms":["shopify","woocommerce","bigcommerce","custom"],"date_added":"2026-03-12","difficulty":"intermediate","import_tag":"clean-skills-v1","description":"Turn your blog into a sales channel by embedding shoppable product cards in editorial content and tracking content-influenced revenue"}},"renderedAt":1782979886526}

Content Commerce Overview Content commerce bridges editorial content — blog posts, buying guides, lookbooks — with direct product purchasing, capturing high-intent organic traffic and shortening the path from discovery to purchase. Shopify and WooCommerce both have built-in blog functionality where you can link products directly; headless setups require a CMS integration. The key goal is making it easy for your editorial team to embed products without engineering help, and tracking which content pieces actually drive revenue. When to Use This Skill - When a blog drives significant organic tra…