Shopify + Google Sheets: blog posts published clean
Your product catalog changes, inventory shifts, promos come and go. But your blog? It’s usually the thing that falls behind because creating posts means copy-pasting product details, chasing approvals, and trying not to publish the same idea twice.
This is the kind of mess Shopify store owners feel first. Marketing managers trying to grow organic traffic get stuck in the same loop. And agencies managing multiple stores? They live here. This Shopify blog automation turns product data into trackable drafts and published posts without the constant busywork.
Below, you’ll see exactly how the workflow runs in n8n, what outcomes to expect, and what you need to set it up so it stays clean as you scale.
How This Automation Works
The full n8n workflow, from trigger to final output:
n8n Workflow Template: Shopify + Google Sheets: blog posts published clean
flowchart LR
subgraph sg0["Start Creation Flow"]
direction LR
n0@{ icon: "mdi:play-circle", form: "rounded", label: "Start Creation", pos: "b", h: 48 }
n1["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/shopify.svg' width='40' height='40' /></div><br/>Get All Product Details"]
n2@{ icon: "mdi:database", form: "rounded", label: "Product Details to Sheet", pos: "b", h: 48 }
n3["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/code.svg' width='40' height='40' /></div><br/>Fix the input format"]
n4@{ icon: "mdi:database", form: "rounded", label: "Update the sheet", pos: "b", h: 48 }
n5@{ icon: "mdi:swap-horizontal", form: "rounded", label: "Filter Duplicates", pos: "b", h: 48 }
n6@{ icon: "mdi:robot", form: "rounded", label: "Magic Room", pos: "b", h: 48 }
n7@{ icon: "mdi:brain", form: "rounded", label: "Gemini", pos: "b", h: 48 }
n8@{ icon: "mdi:robot", form: "rounded", label: "Output Parser", pos: "b", h: 48 }
n9@{ icon: "mdi:brain", form: "rounded", label: "Gemini1", pos: "b", h: 48 }
n10@{ icon: "mdi:cog", form: "rounded", label: "Limit = 1", pos: "b", h: 48 }
n11@{ icon: "mdi:database", form: "rounded", label: "Update Blog Content", pos: "b", h: 48 }
n12["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/code.svg' width='40' height='40' /></div><br/>Fix Content Format"]
n13["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/httprequest.dark.svg' width='40' height='40' /></div><br/>Blog Creation"]
n14@{ icon: "mdi:database", form: "rounded", label: "Status Update", pos: "b", h: 48 }
n15@{ icon: "mdi:cog", form: "rounded", label: "Nothing", pos: "b", h: 48 }
n16@{ icon: "mdi:cog", form: "rounded", label: "Nothing1", pos: "b", h: 48 }
n17@{ icon: "mdi:database", form: "rounded", label: "Update Input table", pos: "b", h: 48 }
n7 -.-> n6
n9 -.-> n8
n10 --> n6
n6 --> n17
n6 --> n11
n13 --> n14
n8 -.-> n6
n14 --> n16
n0 --> n1
n4 --> n5
n5 --> n10
n5 --> n15
n12 --> n13
n11 --> n12
n3 --> n4
n1 --> n2
n2 --> n3
end
%% Styling
classDef trigger fill:#e8f5e9,stroke:#388e3c,stroke-width:2px
classDef ai fill:#e3f2fd,stroke:#1976d2,stroke-width:2px
classDef aiModel fill:#e8eaf6,stroke:#3f51b5,stroke-width:2px
classDef decision fill:#fff8e1,stroke:#f9a825,stroke-width:2px
classDef database fill:#fce4ec,stroke:#c2185b,stroke-width:2px
classDef api fill:#fff3e0,stroke:#e65100,stroke-width:2px
classDef code fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px
classDef disabled stroke-dasharray: 5 5,opacity: 0.5
class n0 trigger
class n6,n8 ai
class n7,n9 aiModel
class n1,n5 decision
class n2,n4,n11,n14,n17 database
class n13 api
class n3,n12 code
classDef customIcon fill:none,stroke:none
class n1,n3,n12,n13 customIcon
The Problem: Blog publishing gets messy at scale
Writing “just one more product post” sounds simple until you do it every week for a catalog of 50, 200, or 1,000 products. You pull titles and descriptions from Shopify, grab images, rewrite everything into a blog format, then try to keep it SEO-friendly and on-brand. Meanwhile, you still need a way to track what’s already been drafted or published. Miss that part and you’ll create duplicates, overwrite a draft, or publish something half-finished. Honestly, the mental load is the worst part.
The friction compounds. Here’s where it breaks down.
- Copying product info into a doc or CMS takes about 20 minutes per post, and it’s easy to miss key specs or benefits.
- Without a single tracking sheet, teams lose track of what’s “drafted,” “needs review,” or already published.
- Duplicate prevention becomes a manual ritual, so it gets skipped when you’re busy.
- Even when the writing is done, turning it into clean HTML for Shopify blog publishing is another tedious step.
The Solution: Generate Shopify blog drafts from product data (then publish)
This n8n workflow starts by pulling your Shopify product catalog, then logging those products into Google Sheets so you have a simple, visible queue. From there, it normalizes the product payload (so fields are consistent), checks the sheet to find unused entries, and processes one product at a time to keep the output predictable. Then Google Gemini generates an SEO-friendly blog draft in structured HTML based on the product’s details. Before anything is published, the workflow sanitizes the HTML so Shopify’s API accepts it cleanly. Finally, it posts the article to Shopify and updates your Google Sheet with the publish status, so you always know what happened.
The workflow begins when you manually launch it (or schedule it later). It pulls products from Shopify, runs a duplicate check in Google Sheets, and sends a single product’s data through Gemini for a draft. After a quick HTML cleanup, the post is published (or drafted) in Shopify and logged back to the sheet.
What You Get: Automation vs. Results
| What This Workflow Automates | Results You’ll Get |
|---|---|
|
|
Example: What This Looks Like
Say you want to publish 10 product-based blog posts each week. Manually, if each post takes about 20 minutes to pull product info, 40 minutes to write, and 10 minutes to format and publish, that’s roughly 70 minutes per post (close to 12 hours weekly). With this workflow, you spend about 10 minutes setting the rules once and then hit run. Gemini drafts the posts, n8n logs everything in Google Sheets, and Shopify publishing happens automatically, so your weekly effort becomes review time instead of production time.
What You’ll Need
- n8n instance (try n8n Cloud free)
- Self-hosting option if you prefer (Hostinger works well)
- Shopify for product data and blog publishing
- Google Sheets to track drafts and prevent duplicates
- Google Gemini API key (get it from Google AI Studio)
Skill level: Intermediate. You’ll connect accounts, paste API credentials, and make small edits to prompts and field mappings.
Don’t want to set this up yourself? Talk to an automation expert (free 15-minute consultation).
How It Works
You launch the run. The workflow starts from a manual trigger, which is perfect for testing. Once you like the output, you can swap in a schedule so it runs daily or weekly.
Product data is pulled and organized. n8n fetches your Shopify catalog, logs products into Google Sheets, and normalizes fields so the AI prompt gets consistent inputs. Clean inputs matter more than people think.
Duplicates are blocked before they happen. An “unused entries” check routes only fresh rows into the generator, then a limit control processes one item at a time. That keeps drafts from colliding and makes troubleshooting much easier.
Gemini drafts, then Shopify receives. The agent node sends product context to Gemini, parses structured output, sanitizes the HTML for API compatibility, and posts the finished article via HTTP request. Google Sheets is updated again with the publish status so your team can review, spot errors, or re-run safely.
You can easily modify the prompt and the “publish vs draft” behavior based on your needs. See the full implementation guide below for customization options.
Step-by-Step Implementation Guide
Step 1: Configure the Manual Trigger
This workflow starts manually so you can run it on demand while you validate your Shopify and Google Sheets setup.
- Add the Manual Launch Trigger node as the trigger for the workflow.
- Flowpast Branding as a visual reference note; it does not affect execution.
Step 2: Connect Shopify and Google Sheets Data Sources
Pull your Shopify product catalog and log it into Google Sheets. Multiple Google Sheets nodes are used for input, refined data, drafts, and status updates.
- Configure Fetch Product Catalog with Resource set to
product, Operation set togetAll, Return All enabled, and Authentication set toaccessToken.
Credential Required: Connect yourshopifyAccessTokenApicredentials. - Set up Log Products to Sheet with Operation set to
appendOrUpdate, Document set to[YOUR_ID], and Sheet set togid=0(row_data). - Map columns in Log Products to Sheet using expressions: title to
{{ $('Fetch Product Catalog').item.json.title }}, Images to{{ $('Fetch Product Catalog').item.json.images }}, handle to{{ $('Fetch Product Catalog').item.json.handle }}, product_id to{{ $('Fetch Product Catalog').item.json.id }}, and description to{{ $('Fetch Product Catalog').item.json.body_html }}.
Credential Required: Connect yourgoogleSheetsOAuth2Apicredentials. - Configure the remaining Google Sheets nodes (Write Refined Sheet, Mark Input Used, Append Blog Drafts, Update Publish Status) with the same Google Sheets document
[YOUR_ID]and their respective sheet IDs (25757113and1548183235).
Credential Required: Connect yourgoogleSheetsOAuth2Apicredentials to all Google Sheets nodes.
Step 3: Normalize Product Data and Filter Unused Entries
This stage converts raw Shopify data into structured fields, stores refined data, and selects one unused entry for drafting.
- In Normalize Product Payload, keep the provided JavaScript to generate
cleanDescription, normalize images, and build the refined payload. - Configure Write Refined Sheet with Operation set to
appendOrUpdateand column mappings: title to{{ $json.title }}, handle to{{ $json.handle }}, Image_1 to{{ $json.imageSources[0] }}, Image_2 to{{ $json.imageSources[1] }}, Image_3 to{{ $json.imageSources[2] }}, Image_4 to{{ $json.imageSources[3] }}, blog_id to[YOUR_ID], product_id to{{ $json.product_id }}, blog_status tounused, and description to{{ $json.cleanDescription }}. - Set Check Unused Entries to allow items where blog_status equals
unusedor is empty using expressions{{ $json.blog_status }}with Right Valueunusedand. - Leave Limit to Single Item as-is to process only one product per run.
- Route the false path of Check Unused Entries to No Action Path to safely exit if there are no unused entries.
Step 4: Set Up the AI Draft Composer
The AI pipeline generates structured blog drafts using Gemini and a strict output parser.
- In AI Draft Composer, set Text to
=Input fields provided: \n- Title: {{ $json.title }}\n- Description: {{ $json.description }}and leave Prompt Type asdefinewith Has Output Parser enabled. - Connect Gemini Model Bridge as the AI language model for AI Draft Composer.
Credential Required: Connect yourgooglePalmApicredentials. - Attach Structured Output Parser to AI Draft Composer and keep Auto Fix enabled with the JSON schema example provided.
Credential Required: Credentials for parsers should be added to the parent model—ensure Gemini Parser Model hasgooglePalmApicredentials. - Connect Gemini Parser Model as the language model for Structured Output Parser.
Credential Required: Connect yourgooglePalmApicredentials.
blog_title, content, and metadata.Step 5: Configure Draft Logging and Publishing
After AI drafting, the workflow logs drafts, sanitizes HTML, publishes to Shopify, and updates status in Google Sheets.
- AI Draft Composer outputs to both Mark Input Used and Append Blog Drafts in parallel.
- In Mark Input Used, set product_id to
{{ $('Limit to Single Item').item.json.product_id }}and blog_status toused.
Credential Required: Connect yourgoogleSheetsOAuth2Apicredentials. - In Append Blog Drafts, set content to
{{ $json.output.content }}, excerpt to{{ $json.output.excerpt }}, blog_title to{{ $json.output.blog_title }}, page_title to{{ $json.output.page_title }}, product_id to{{ $('Limit to Single Item').item.json.product_id }}, URL _handle to{{ $('Limit to Single Item').item.json.handle }}, blog_status togenerated, and meta_description to{{ $json.output.meta_description }}.
Credential Required: Connect yourgoogleSheetsOAuth2Apicredentials. - Keep Sanitize Blog HTML as-is to escape HTML for Shopify JSON compatibility.
- Configure Publish Blog Article with URL set to
https://[YOUR_SHOP].myshopify.com/admin/api/2025-07/blogs/[YOUR_ID]/articles.json, Method set toPOST, and JSON Body set to={ "article": { "title": "{{ $json.blog_title }}", "author": "[YOUR_NAME]", "tags": "Electronics", "body_html": "{{ $json.body_html }}", "published_at": "{{$now}}" } }.
Credential Required: Connect yourshopifyAccessTokenApicredentials. - In Update Publish Status, set article_id to
{{ $json.article.id }}, product_id to{{ $('Append Blog Drafts').item.json.product_id }}, and blog_status toposted.
Credential Required: Connect yourgoogleSheetsOAuth2Apicredentials. - Allow Update Publish Status to complete at No Action End for a clean termination path.
[YOUR_SHOP], [YOUR_ID], or [YOUR_NAME] in Publish Blog Article, Shopify will reject the request.Step 6: Test and Activate Your Workflow
Run a manual test to verify the full end-to-end flow before enabling in production.
- Click Execute Workflow to trigger Manual Launch Trigger and monitor each node’s output.
- Confirm new rows appear in the sheets updated by Log Products to Sheet, Write Refined Sheet, Append Blog Drafts, and Update Publish Status.
- Verify that Publish Blog Article returns an
article.idand the Shopify blog post appears as expected. - If no unused items are found, confirm the workflow safely exits via No Action Path.
- Once successful, save the workflow and activate it for scheduled or manual production runs.
Common Gotchas
- Shopify credentials can expire or need specific permissions. If things break, check your Shopify private app/custom app access token scopes first (and confirm the blog/article endpoints are allowed).
- If you’re using Wait nodes or external rendering, processing times vary. Bump up the wait duration if downstream nodes fail on empty responses.
- Default prompts in AI nodes are generic. Add your brand voice early or you’ll be editing outputs forever.
Frequently Asked Questions
About 45 minutes if your Shopify, Sheets, and Gemini access are ready.
No coding is required for the basic setup. You’ll mostly map fields, connect credentials, and adjust the Gemini prompt to match your store.
Yes. n8n has a free self-hosted option and a free trial on n8n Cloud. Cloud plans start at $20/month for higher volume. You’ll also need to factor in Gemini API usage costs, which depend on your model and how long your articles are.
Two options: n8n Cloud (managed, easiest setup) or self-hosting on a VPS. For self-hosting, Hostinger VPS is affordable and handles n8n well. Self-hosting gives you unlimited executions but requires basic server management.
Yes, but you’ll want to do it intentionally. Keep the same Shopify fetch and Google Sheets tracking, then adjust the “Publish Blog Article” HTTP request to create drafts (or route to a “needs review” path) instead of publishing immediately. Common customizations include changing the prompt structure, adding internal links between related products, and generating multi-language versions for specific collections.
Usually it’s an access token scope issue or an expired token. Regenerate your Shopify access token, confirm it can read products and write blog articles, then update the credential in n8n. If it fails only sometimes, you may also be hitting Shopify API throttling, especially when you pull a large catalog and run drafts back-to-back.
A lot.
For AI-driven blog pipelines like this, n8n is usually the more comfortable fit because you can branch, loop one product at a time, and sanitize HTML before publishing without paying extra for “premium” logic steps. You also get the option to self-host, which matters when you’re generating lots of drafts across a big catalog. Zapier or Make can still work, but the moment you need structured parsing, conditional duplicate checks, and a publish-status feedback loop, the scenario tends to sprawl. If you want simple “new row in sheet → create draft” and nothing else, they may be faster to set up. If you’re unsure, Talk to an automation expert and get a straight recommendation.
Once this is running, your blog stops being a “someday” project. It becomes a system that quietly ships content while you focus on merchandising, offers, and growth.
Need Help Setting This Up?
Our automation experts can build and customize this workflow for your specific needs. Free 15-minute consultation—no commitment required.