Template-Based Content (pSEO)

What is Template-Based Content?

Template-based content generation (also known as Programmatic SEO or pSEO) is a strategy for creating large numbers of targeted pages at scale. Instead of manually writing hundreds of similar pages, you create templates and combine them with data to generate unique, valuable content automatically.

Common use cases include:

  • Location pages: "Best Coffee Shops in [City]" for 500 cities
  • Product comparisons: "[Product A] vs [Product B]" for all product pairs
  • Tool/Calculator pages: "[Number] [Unit] to [Other Unit]" converters
  • Directory listings: "[Business Type] in [Location]"
  • How-to guides: "How to [Action] with [Tool]" for many combinations

How Template Mode Works

Publish Owl's template system combines three elements:

1. Data Source

A spreadsheet (CSV or Google Sheets) with your variables. Each row becomes one article.

2. Templates

HTML templates with placeholders like {'{{city}}'} that get replaced with your data.

3. AI Sections

Dynamic content blocks where AI generates unique content based on your data.

Step 1: Prepare Your Data

Create a spreadsheet with columns for each variable you want to use. The first row should contain column headers (these become your variable names).

Example: Coffee Shop Directory

city state population known_for
Seattle Washington 750,000 Starbucks origin
Portland Oregon 650,000 Third-wave coffee
Austin Texas 1,000,000 Local roasters

Data Source Options

  • CSV Upload: Upload a .csv file directly to Publish Owl
  • Google Sheets: Paste a link to a public Google Sheet
Tip: Column headers become variable names. Use simple, lowercase names without spaces (e.g., city, state, known_for).

Step 2: Create a Template Workflow

  1. Go to the Create page
  2. Select Programmatic (pSEO) from the content type cards
  3. Upload your CSV or connect Google Sheets in the input step
  4. Click Continue to enter the pSEO workflow editor
  5. Enter a name (e.g., "Coffee Shop Directory")
  6. The pSEO editor has its own tab structure: Data Source, Templates, AI Sections, Conditions, and Enrichment

Step 3: Connect Your Data Source

Option A: CSV Upload

  1. In the Data Source section, select CSV
  2. Click the upload area or drag and drop your CSV file
  3. Publish Owl will parse the file and show you the available columns

Option B: Google Sheets

  1. Open your Google Sheet and click Share (top right)
  2. Under "General access", select "Anyone with the link" (Viewer is fine)
  3. Copy the URL from your browser's address bar
  4. Paste the URL into the Google Sheets field in Publish Owl
  5. Click Load Sheet to preview your columns
  6. Click Use This Sheet to confirm

Tip: If your data is on a specific tab, navigate to that tab before copying the URL. The URL includes the tab ID automatically.

Google Sheets Advantage: When you update your Google Sheet, Publish Owl can automatically detect changes. This is great for ongoing template campaigns where you regularly add new data.

Step 4: Create Your Templates

Templates use double curly braces to insert data: {'{{variable_name}}'}

Title Template

Best Coffee Shops in {'{{city}}'}, {'{{state}}'} (2026 Guide)

Becomes: "Best Coffee Shops in Seattle, Washington (2026 Guide)"

Slug Template

best-coffee-shops-{'{{city}}'}-{'{{state}}'}

Becomes: "best-coffee-shops-seattle-washington"

Content Template (HTML)

<p>Looking for the best coffee shops in {'{{city}}'}? With a population
of {'{{population}}'}, {'{{city}}'} has developed a vibrant coffee culture
known for {'{{known_for}}'}. </p>

<h2>Top Coffee Shops in {'{{city}}'}</h2>
{'{{AI:top_shops}}'}

<h2>Coffee Culture in {'{{state}}'}</h2>
{'{{AI:coffee_culture}}'}

<h2>Tips for Finding Great Coffee in {'{{city}}'}</h2>
{'{{AI:tips}}'}

Content Variation (Spin Syntax)

To avoid repetitive content across hundreds of pages, use spin syntax to create variations. The format is {'{option1|option2|option3}'} - the system randomly picks one option per article. You can include as many options as you want (2, 5, 10, or more).

{'{Welcome to|Discover|Explore}'} our {'{guide|resource|article}'} on {'{{city}}'}.

{'{Looking for|Searching for|Want to find}'} the best coffee in {'{{city}}'}?
{"{You've come to the right place|We've got you covered|Look no further}"}!

Each article gets a unique combination, making your content feel more natural at scale.

Special Template Variables

In addition to your data columns, templates support special built-in variables:

  • {'{{toc}}'} - Inserts an auto-generated table of contents with anchor links based on your H2/H3 headings
  • {'{{AI:section_name}}'} - AI-generated content for the named section (see below)
  • {'{{current_year}}'} - The current year (e.g., 2026)
  • {'{{current_date}}'} - The current date
<p>Introduction to coffee in {'{{city}}'}...</p>

{'{{toc}}'}

<h2>History of Coffee in {'{{city}}'}</h2>
<p>Content here...</p>

<h2>Top Coffee Shops</h2>
{'{{AI:top_shops}}'}

<h2>Tips for Coffee Lovers</h2>
{'{{AI:tips}}'}

The {'{{toc}}'} variable automatically detects all H2/H3 headings and creates a navigable table of contents with anchor links.

Step 5: Configure AI Sections

AI sections are placeholders like {'{{AI:section_name}}'} that get replaced with AI-generated content. Each section needs a prompt telling the AI what to write.

Adding AI Sections

  1. Scroll to the AI Sections area
  2. Click + Add AI Section
  3. Enter the section name (must match your template, e.g., "top_shops")
  4. Write a prompt for the AI
  5. Repeat for each AI section in your template

Example Prompts

Section: top_shops
Prompt: Write about 5 popular coffee shops in {'{{city}}'}, {'{{state}}'}.
For each shop, include the name, a brief description of the
atmosphere, and what they're known for. Use h3 tags for shop names.

---

Section: coffee_culture
Prompt: Describe the coffee culture in {'{{state}}'}, mentioning
{'{{city}}'} specifically. Discuss local roasters, popular brewing
styles, and what makes the area's coffee scene unique.
Keep it to 2-3 paragraphs.

---

Section: tips
Prompt: Provide 5 practical tips for finding great coffee in
{'{{city}}'}. Format as a numbered list. Include advice about
exploring neighborhoods, asking locals, and what to look for
in a quality coffee shop.
Tip: You can use data variables in AI prompts! The AI will receive the actual values when generating content, making each article unique.

Conditional Sections

Show or hide content based on your data. This is useful when some rows have data that others don't, or when you want to display different content based on values.

Creating Conditional Sections

  1. Go to the Conditions tab
  2. Click + Add Conditional Section
  3. Name your section (e.g., "reviews_section")
  4. Set the condition (variable + operator + value)
  5. Add content to show when the condition is true
  6. Optionally add alternative content when false
  7. Reference in your template as {'{{conditional.section_name}}'}

Available Operators

  • exists / is not empty: Show content only when a column has data
  • equals / does not equal: Compare to a specific value
  • contains: Check if text contains a substring
  • is greater than / is less than: Numeric comparisons
  • is true / is false: Boolean checks

Example: Show Reviews Only When Available

Condition: review_count "is not empty"

Content when true:
<h2>Customer Reviews</h2>
<p>This coffee shop has {'{{review_count}}'} reviews with an average
rating of {'{{rating}}'} stars.</p>

Content when false: (leave empty to hide section entirely)

Example: Price Comparison

Condition: price "is less than" variable competitor_price

Content when true:
<p class="highlight">Great value! This is cheaper than competitors.</p>

Content when false:
<p>Premium pricing reflects the quality experience.</p>

Featured Images

Configure how featured images are generated for your template articles. Go to the Images tab to set up one of four image modes.

Image Modes

  • From Data Column: Use image URLs from your spreadsheet. Select a column containing image URLs.
  • AI Generated: Generate unique images using AI. Available providers include GPT Image 1.5 (recommended), GPT Image 1, Gemini, Flux (Pro, Max, Ultra), Stable Diffusion, Ideogram, xAI Grok, and Replicate. Write a prompt template using your variables.
  • Stock Photos: Search Pexels, Unsplash, or Pixabay using a search template based on your data.
  • Image Template: Use a Fabric.js template you've created in the Template Editor. Map template variables to your data columns.

AI Image Prompt Example

A cozy coffee shop interior in {'{{city}}'}, {'{{state}}'}.
Warm lighting, wooden tables, and customers enjoying drinks.
Professional photography style, 16:9 aspect ratio.

Each article gets a unique image based on its data values.

Stock Photo Search Template

coffee shop {'{{city}}'}

Searches for relevant stock photos based on your data.

Tip: You can also add in-article images using the same modes. Enable "In-Article Images" and reference them in your template.

AI Image Provider Options

Each AI image provider offers different capabilities and configuration options:

  • GPT Image 1.5 (Recommended): OpenAI's latest model with reference image support for style transfer, background options (transparent/opaque), and output format selection (PNG/JPEG/WebP).
  • Gemini: Google's image generation with the gemini-2.5-flash-image model.
  • Flux: Multiple model tiers - flux-2-pro (default), flux-2-max (maximum quality), flux-2-flex (configurable steps/guidance), flux-pro-1.1-ultra with "Raw" mode for natural aesthetics.
  • Stable Diffusion: 40+ style presets including photographic, cinematic, anime, digital-art, fantasy-art, pixel-art, and more.
  • Ideogram: Style types (AUTO, REALISTIC, DESIGN, FICTION), 50+ style presets (WATERCOLOR, ART_DECO, CINEMATIC, etc.), color palettes, and Magic Prompt enhancement.
  • xAI Grok: Uses the grok-imagine-image-pro ($0.07/image) or grok-imagine-image ($0.02/image) models.
  • Replicate: Access to open-source models including Flux Schnell, Flux Dev, SDXL, and more. Supports custom model IDs.

Amazon Product Integration

Automatically fetch product data from Amazon to include in your articles. Requires Amazon PA API credentials configured in Settings.

Setup

  1. Go to Settings and add your Amazon PA API credentials
  2. In your template workflow, go to the Amazon tab
  3. Enable Amazon product data
  4. Choose how to get products: from a column (ASIN/URL) or by keyword search

Product Data Modes

  • From Column: Your data contains Amazon ASINs or product URLs. Select the column containing them.
  • Keyword Search: Search Amazon using a value from your data. Set max products per article (up to 20).

Available Product Variables

{'{{product_title}}'} {'{{product_price}}'} {'{{product_affiliateUrl}}'} {'{{product_imageUrl}}'} {'{{product_rating}}'} {'{{product_reviewCount}}'} {'{{product_asin}}'}

For multiple products, use numbered variables: {'{{product1_title}}'}, {'{{product2_title}}'}, etc.

Example Template Usage

<div class="product-card">
  <img src="{'{{product_imageUrl}}'}" alt="{'{{product_title}}'}">
  <h3>{'{{product_title}}'}</h3>
  <p class="price">{'{{product_price}}'}</p>
  <p>{'{{product_rating}}'} stars ({'{{product_reviewCount}}'} reviews)</p>
  <a href="{'{{product_affiliateUrl}}'}">Check Price on Amazon</a>
</div>

Internal Linking

Automatically add internal links between your pSEO articles to improve SEO and user navigation. Go to the Linking tab to configure.

Linking Scopes

  • Within Batch Only: Link only between articles in the same pSEO batch. Fast, no AI required.
  • Site-Wide: Link to any relevant article from your indexed site content. Uses AI embeddings for relevance matching.
  • Both: Combine batch linking with site-wide for maximum coverage.

Page Index Limits

Site-wide linking requires indexing your site's pages via sitemap. Index limits by plan:

  • Standard: Up to 500 pages
  • Pro: Up to 10,000 pages

Use sitemap filters (include/exclude patterns, child sitemap selection) to target the most relevant pages if your site exceeds these limits.

Batch Linking Settings

  • Max links per article: How many internal links to add (e.g., 3)
  • Anchor text: Use article titles, a specific column, or a custom template
  • URL pattern: Default is /slug, or customize like /blog/{'{{slug}}'}

How It Works

The system uses vector embeddings to find semantically relevant articles, then applies LLM validation to ensure links are contextually appropriate. The system searches your article content for the anchor text of matched articles. When found, that text becomes a link. If the anchor text doesn't appear naturally, the link is added to a "Related Articles" section at the end.

Advanced Configuration

  • Relevance Thresholds: Set minimum and maximum relevance scores (0-1.0) to control link quality. Higher minimums mean stricter matching.
  • URL Patterns: Use regex patterns to include or exclude specific URLs (e.g., exclude /tag/* pages, only include /blog/* URLs).
  • Distribution Strategy: Choose "spread" to distribute links evenly throughout the article, or "clustered" to group them in specific sections.
  • Related Links Position: Configure where the "Related Articles" section appears when inline linking isn't possible (end, after intro, before conclusion).
  • Per-Article Control: In the site's Link Index management, you can toggle individual articles on/off for linking.

Hardcoded Links from Data

You can also add specific links from your data columns. This is useful for:

  • Affiliate product links stored in your spreadsheet
  • Source citations or reference links
  • Related article URLs you've predetermined

Data Enrichment (Web Scraping)

Scrape data from URLs in your dataset to create new variables. Enrichment runs before template processing, so scraped values are available as variables in your templates.

Setting Up Enrichment

  1. Go to the Enrichment tab
  2. Enable data enrichment
  3. Name your scraper (e.g., "Competitor Data")
  4. Select the URL source (column or template)
  5. Add data selectors to extract specific content

URL Source Options

  • From Column: Select a column containing full URLs
  • URL Template: Build URLs dynamically, e.g., https://example.com/{'{{slug}}'}

Data Selectors

Choose preset selectors or write custom CSS selectors:

  • Title: Extracts page title (title, h1, og:title)
  • Content: Main content (article, main, .content)
  • Description: Meta description
  • Price: Price elements (.price, [data-price])
  • Images/Links: Extract image URLs or link hrefs
  • Custom: Any CSS selector like .product-title or #rating

Scraper Providers

  • Free Scraper: 20 requests per hour limit. Good for testing.
  • ScrapingBee: Unlimited requests with proxy rotation and CAPTCHA handling. Requires API key in Settings.

Using Scraped Data

Scraper name: competitor_data
Selector label: competitor_price

In your template:
<p>Competitor price: {'{{scraped_competitor_data_competitor_price}}'}</p>

Scraped variables follow the pattern: {'{{scraped_[scraper]_[selector]}}'}

Note: Web scraping adds time to article generation. Use it only when you need live data from external sources that can't be included in your spreadsheet.

Schema Markup (Structured Data)

Schema markup adds structured data to your articles that helps search engines understand your content. This can enable rich snippets in Google search results - FAQ dropdowns, star ratings, how-to steps, and more.

Enabling Schema Markup

  1. Go to the Article tab in your template workflow configuration
  2. Toggle Enable Schema Markup on
  3. Select a schema type from the dropdown
  4. Click Load Starter Template to get a pre-built template
  5. Customize the template with your data variables

Available Schema Types

  • Article: General articles and blog posts
  • BlogPosting: Blog-specific content
  • NewsArticle: News and press releases
  • Product: Product pages with pricing and ratings
  • FAQPage: Question and answer pages (enables FAQ rich snippets)
  • HowTo: Step-by-step guides (enables how-to rich snippets)
  • LocalBusiness: Business listings with address and contact info
  • Review: Product or service reviews with ratings

Using Variables in Schema

Schema templates use the same {'{{variable}}'} syntax as content templates. You can use both data columns and AI sections:

{`{
  "@context": "https://schema.org",
  "@type": "Article",
  "headline": "{{title}}",
  "description": "{{meta_description}}",
  "author": {
    "@type": "Person",
    "name": "{{author_name}}"
  }
}`}

Variable values are automatically escaped for JSON (quotes, newlines, etc.).

FAQ and HowTo Templates

For FAQPage and HowTo schemas, starter templates include 10 slots for questions/steps. Empty slots are automatically removed during processing, so articles with fewer items work perfectly.

{`"mainEntity": [
  { "@type": "Question", "name": "{{question_1}}", "acceptedAnswer": ... },
  { "@type": "Question", "name": "{{question_2}}", "acceptedAnswer": ... },
  ...
  { "@type": "Question", "name": "{{question_10}}", "acceptedAnswer": ... }
]`}

If your data only has 5 questions, items 6-10 are automatically removed from the final output.

Preview Tip: Use the Save & Preview button, then toggle to HTML view to see your schema markup in the generated content. The schema appears as a <script type="application/ld+json"> block at the top.
Validation: After publishing, test your pages with Google's Rich Results Test to ensure the schema is valid and eligible for rich snippets.

Step 6: Generate Your Articles

Once your workflow is configured, you're ready to generate articles.

Preview First

Use the Preview button to see how your template looks with sample data before generating. This helps catch errors in your templates.

Batch Generation

  1. Save your workflow
  2. Go to the Jobs page and select your template workflow from the filter
  3. The batch panel will appear - select which rows to process (all, specific range, or unprocessed only)
  4. Optionally enable Drip Publishing to schedule articles over time
  5. Click Generate All Articles

Drip Publishing

Publishing hundreds of articles at once can look unnatural to search engines. Drip publishing spreads your articles over days or weeks.

Configuration Options

  • Articles per day: How many to publish each day (e.g., 10)
  • Start date: When to begin publishing
  • Start time: What time to publish (e.g., 9:00 AM)
  • Spread throughout day: Distribute articles across hours instead of all at once

Example

300 articles, 10 per day, starting January 15th = 30 days to publish all content

Note: Drip publishing requires a CMS that supports scheduled posts. WordPress and Ghost support this natively. For other platforms, articles will be generated on schedule but may publish immediately.

Best Practices

1. Ensure Unique Value

Each page should provide genuine value. Combine static templates with AI-generated content to ensure uniqueness while maintaining quality.

2. Start Small

Generate 5-10 test articles first. Review them for quality, check for template errors, and refine your prompts before scaling up.

3. Use Descriptive Variable Names

Name columns clearly: city_name is better than col1. This makes templates more readable and maintainable.

4. Leverage Internal Linking

Enable internal linking to automatically connect related template pages. This helps search engines discover and understand your content structure.

5. Monitor and Iterate

After publishing, monitor performance in Google Search Console. Update templates and regenerate content for underperforming pages.

Was this helpful?