All posts
Guide

Automating Publishing With the SearchFit CLI and GitHub Actions

Integrate SearchFit CLI with GitHub Actions to automate AI-optimized content publishing. Eliminate manual deploys and get content live in ChatGPT, Perplexity

KKevin10 minutes read

When your page gets zero citations in ChatGPT, Perplexity, or Gemini while a competitor’s blog post appears as a source three times in the same thread, the traffic leak is already a revenue leak. AI answer engines now surface citations without sending visitors to your domain. That means every week you spend manually pushing content through a review chain instead of choosing to automate publishing is a week your visibility sits at 0%, while the competitor who automated the pipeline eats your lunch.

Publishing answer-engine-optimized content on a regular cadence isn’t a nice-to-have; it’s the price of staying cited. The fix is a pipeline that generates, validates, and deploys content without a human babysitting each step. That’s exactly what we’ll build here: a continuous publishing workflow using the SearchFit CLI and GitHub Actions. By the end, you’ll have a repo that automatically generates AI‑first content, pushes it to your static site, and publishes it on a cron schedule. No manual file uploads, no forgetting to hit “deploy.”

Prerequisites

Before you start coding the workflow, make sure you have these pieces in place:

  • A GitHub repository where your website source lives (Hugo, Next.js static export, or plain Markdown).
  • A SearchFit account with an active API key. If you haven’t created one yet, the OAuth and API Key Management in SearchFit guide walks through scoping a key with just the permissions this workflow needs.
  • The SearchFit CLI installed locally for initial testing. You can grab it via npm: npm install -g @searchfit/cli.
  • Basic familiarity with YAML and the GitHub Actions workflow syntax. The GitHub Actions documentation is your friend if you need a refresher.
  • A Netlify, Vercel, or GitHub Pages target for automated deploys. We’ll use Netlify in the example, but the pattern works identically for any static host.

Also, skim SearchFit API Rate Limits and Best Practices so you don’t slam the API and get throttled mid-publish. The CLI respects rate limits automatically, but it’s good to know what’s happening under the hood.

Step 1: Installing and Authenticating the SearchFit CLI

We’ll run the CLI inside a GitHub Actions runner, but first confirm everything works on your local machine. Install the CLI globally:

npm install -g @searchfit/cli

Then authenticate with your API key:

searchfit auth --key your-api-key-here

This writes a config file to ~/.searchfit/config.json. The runner will need that file, so we’ll store the key as a GitHub secret and recreate the config on the fly. More on that in a moment.

Test the connection by running a quick visibility check:

searchfit visibility --domain yoursite.com

You should see a report of citation counts across engines. If you’re staring at zeros, that’s exactly why automated publishing matters. More on that diagnostic later.

Pro tip: Use a dedicated API key with only the scopes needed for generation and publishing. The OAuth and API Key Management guide shows how to create a tightly scoped key that can’t access billing or admin endpoints, limiting blast radius if the key ever leaks.

Step 2: Generating Answer-Engine-Optimized Content with the CLI

The core of the workflow is the searchfit generate command. It invokes the SearchFit agent team, Researcher, Writer, Validator, Scorer, to produce content engineered for AI citations. The agents run in sequence: they research the top-ranking content across ChatGPT, Perplexity, Gemini, Claude, and Grok; draft a piece that matches what those engines reward; validate factual consistency; and then score it against the top 3 cited URLs. You get a pull‑ready Markdown file.

Here’s a minimal command:

searchfit generate \
  --keyword "answer engine optimization for SaaS" \
  --output content/blog/aeo-saas-guide.md \
  --engine chatgpt,perplexity,gemini

You can target multiple keywords in one run by passing a CSV file with a list of keywords and desired slugs. That’s what we’ll automate later.

The CLI writes the file and also outputs a JSON summary. Keep that JSON; we’ll use it for validation in the GitHub Actions step.

For a deeper dive into custom generation pipelines, the post on Building Custom AEO Workflows With the SearchFit API covers every flag and parameter. You can control tone ("confident, no fluff"), target engines, and even benchmark against competitor URLs.

Step 3: Setting Up Your GitHub Actions Workflow

Now we move the CLI into a GitHub Actions runner. Create a file at .github/workflows/publish‑content.yml. The workflow will:

  1. Check out the repo.
  2. Set up Node.js (the CLI depends on Node).
  3. Install the SearchFit CLI.
  4. Authenticate using a repository secret.
  5. Run searchfit generate to create new content.
  6. Commit and push the updated content files back to the repo.
  7. Trigger a deploy.

Here’s the full YAML:

name: Publish AI-Optimized Content

on:
  schedule:
    - cron: '0 4 * * 1'  # Every Monday at 04:00 UTC
  workflow_dispatch:      # Allow manual runs

jobs:
  generate-and-publish:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'

      - name: Install SearchFit CLI
        run: npm install -g @searchfit/cli

      - name: Authenticate CLI
        run: |
          mkdir -p ~/.searchfit
          echo '{"apiKey": "${{ secrets.SEARCHFIT_API_KEY }}"}' > ~/.searchfit/config.json

      - name: Generate content
        run: |
          searchfit generate \
            --keyword-file content/keywords.csv \
            --output-dir content/blog/ \
            --engine chatgpt,perplexity,gemini,claude

      - name: Commit and push new content
        run: |
          git config user.name "searchfit-bot"
          git config user.email "[email protected]"
          git add content/blog/
          git diff --quiet HEAD || git commit -m "auto: publish AI-optimized content [skip ci]"
          git push

      - name: Trigger Netlify deploy
        run: curl -X POST -d {} ${{ secrets.NETLIFY_BUILD_HOOK }}

A few details to note:

  • Authentication: GitHub encrypts the secret SEARCHFIT_API_KEY. The step writes it to a config file the CLI expects. Never hardcode the key.
  • Keyword file: Instead of hardcoding keywords, we maintain content/keywords.csv in the repo. Each row is keyword,slug. The CLI reads this file and generates a separate Markdown file for each line. That makes the pipeline data‑driven: update the CSV, commit, and the next run picks up the new targets.
  • Git config: The bot commits only if there are changes (git diff --quiet HEAD). The [skip ci] tag prevents an infinite loop if your workflow triggers on pushes.
  • Deploy hook: Netlify’s build hook URL is stored as a secret. If you use GitHub Pages, swap that step for the GitHub Pages action.

This is the simplest working pipeline. The DigitalOcean tutorial on setting up a continuous deployment pipeline with GitHub Actions walks through a similar pattern if you want to add test stages.

Step 4: Automate Content Publishing via cron

Schedule is the whole point. Without a cron trigger, you’re still manually running a workflow, just with a pretty UI. We use a cron expression that fires every Monday at 4 AM UTC. That way, fresh content is ready for the workweek.

If you’re not a cron wizard, paste 0 4 * * 1 into Crontab Guru to verify the exact schedule. You can adjust: daily (0 4 * * *), twice a week (0 4 * * 1,4), or even hourly, but hourly requires caution with API rate limits (see the rate limits guide).

Remember that GitHub Actions schedules are subject to delays during high load; expect runs to start within 15-30 minutes of the cron time. If precision matters, run the workflow more frequently and use a conditional on the current day/hour.

The workflow_dispatch event lets you trigger the pipeline on demand. Handy for testing or when a competitive insight demands a same-day response.

Step 5: Validating Output and Handling Errors

A fully automated pipeline without validation is dangerous. You don’t want the bot to publish a hallucinated statistic and have it quoted by Gemini before you wake up. The SearchFit CLI’s built‑in agents handle a lot of validation, but we can add a gate.

Modify the “Generate content” step to capture the JSON summary and run a quick check:

      - name: Generate content
        id: generate
        run: |
          searchfit generate \
            --keyword-file content/keywords.csv \
            --output-dir content/blog/ \
            --engine chatgpt,perplexity,gemini,claude \
            --summary output.json
          echo "citation_score=$(jq '.aggregate_score' output.json)" >> $GITHUB_OUTPUT

      - name: Block publish if score too low
        if: steps.generate.outputs.citation_score < 80
        run: |
          echo "Content failed validation (score: ${{ steps.generate.outputs.citation_score }}). Exiting."
          exit 1

This requires jq (pre‑installed on Ubuntu runners). It reads the aggregate quality score the Scorer agent assigns, and if it’s below a threshold (80, on a 0-100 scale), the workflow fails. No content gets pushed or deployed. You’ll get a GitHub notification, and you can manually inspect the output.

For deeper validation, you can tap into the Real-Time Citation Monitoring via the SearchFit API. That endpoint streams citation events, so you could build a post‑publish validation that waits 24 hours and then checks if your new page got cited, and re‑triggers generation if not. But that’s a topic for another workflow.

Warning: GitHub Actions doesn’t allow a step to save artifacts after a failure by default. If you want to inspect the generated content even when validation fails, add a step that uploads the content/blog/ directory as an artifact using actions/upload-artifact@v4. That way you can debug without manually re‑running locally.

Step 6: Deploying to Production

Now that approved content is committed to the repo, the final step is to push it live. The exact deploy command depends on your host. Here are patterns for the three most common:

  • Netlify: Use the Build Hook URL we stored as a secret. The curl POST in the previous YAML triggers a new deploy. Netlify’s deploy docs confirm this is the canonical way to automate from external systems.
  • GitHub Pages with Hugo: If your site is a Hugo project, add a step that runs hugo and then uses the GitHub Pages action to publish the public/ directory to the gh-pages branch. The Hugo Documentation has example Actions workflows that integrate perfectly.
  • Vercel: Vercel’s GitHub integration automatically deploys on push, so nothing extra is needed. But you may want to add a step that pings the Vercel deploy hook to ensure it catches commits made by the bot (since some integrations ignore bot commits).

For static sites, the pattern is always the same: build the site (if needed) and push the final assets to the host’s deployment endpoint.

One nuance: when your content includes dynamic elements like “last updated” dates, ensure the build step regenerates those. Hugo and other static generators handle this natively when you run a fresh build.

If you want to tie deployment directly to AI performance, the SearchFit Now Integrates Google Analytics: Close the AEO Loop guide shows how to connect GA4 conversion data to your citation metrics. That data can feed into a decision to deploy or not, for example, you could only deploy articles whose AI referral traffic in the last 30 days meets a threshold.

Pro Tips for a Bulletproof CI Pipeline

The workflow above gets you running. Here are operational tweaks that separate a “weekend project” from a production pipeline.

1. Use Semantic Versioning for Content

Tag each published batch with a semantic version (e.g., v1.2.0) using git tag. Then your deploy can reference the tag. If a generation run introduces a regression (say, a scorer bug surfaces), you can immediately roll back to a previous tag rather than hunting through commit history.

      - name: Tag and push version
        run: |
          VERSION=$(date +%Y.%m.%d-%H%M)
          git tag "content-$VERSION"
          git push --tags

2. Parallelize Keyword Batches

If you have 50+ keywords, running them sequentially can take 30+ minutes, and risk runner timeout. Split the keyword file into chunks and use a matrix strategy to run multiple jobs in parallel. The CLI is concurrency‑safe as long as each job writes to a unique output directory (e.g., content/blog/batch-1). Combine the directories before commit.

The SearchFit API Rate Limits and Best Practices article details how to chunk requests for optimal throughput.

3. Monitor Citation Drops Automatically

After publishing, hook the Real-Time Citation Monitoring API into your alerting stack (PagerDuty, Slack). Set a threshold: if a page’s citation count across engines drops by 30% within 48 hours, trigger a re‑generation for that keyword. That closes the loop between publishing and real‑world AI visibility.

4. Integrate With Other Automation Platforms

If you already use n8n or Zapier, you can extend this pipeline. For instance, after a successful deploy, an n8n webhook can update your content calendar and post to Slack. The Integrating SearchFit With n8n for Self-Hosted Teams and Integrating SearchFit With Zapier in 10 Minutes guides show exactly how to wire those together.

5. Cache Dependencies

The npm install -g @searchfit/cli step can add 30-60 seconds per run. Use the actions/cache action to store the global node_modules and skip installation when the CLI version hasn’t changed. This is a small optimization but matters when you run the workflow multiple times a day.

Conclusion

Manual content publishing is a bottleneck that hands your AI visibility to competitors who automate. By piping the SearchFit CLI through GitHub Actions, you create a repeatable, scheduled pipeline that generates answer-engine-optimized content and pushes it live without your hand on the mouse. The result: fresh, AI‑cited articles that keep your brand visible in ChatGPT, Perplexity, Gemini, and other engines.

Key takeaways:

  • A cron‑triggered GitHub Actions workflow eliminates the human lag between content creation and AI citation.
  • Authenticate the CLI via a repository secret and a bootstrapped config file, never commit credentials.
  • Validate output with the Scorer agent’s aggregate score and fail the build if quality is below threshold.
  • Standardize on a keyword CSV to make the pipeline data‑driven; adding a keyword is as simple as a commit.
  • Deploy to Netlify, Hugo/GitHub Pages, or Vercel in one extra step, closing the final loop.
  • Extend with real‑time citation monitoring to trigger re‑generation when visibility slips.

Now, go set up that workflow. The first time you wake up to a Monday morning commit from searchfit-bot and see your page cited in a ChatGPT thread, you’ll know you’ve stopped the leak.

Get SearchFIT Weekly

What we are learning about getting brands cited in AI search, in your inbox every week. Unsubscribe any time.