SEO Blog Admin

Tenant integration guide

Publish approved SEO pages into your own website.

Wotaso finds opportunities, drafts content, supports review, and schedules publishing. Git-backed sites can publish through commits. Nine stable CMS adapters cover WordPress, Webflow, Wix, Contentful, Sanity, Strapi, Ghost, Shopify, and HubSpot; Framer's Server API path remains beta, and custom publishers can use a separately selected webhook connector.

Wotaso

Research, briefs, drafts, review, schedule, learning.

Publishing adapter

Commits files, writes CMS items, or calls a private publisher.

Your website

Static or server-rendered pages, CDN assets, sitemap, analytics.

1. Choose path

Match the real platform

Git-backed frameworks use file publishing. Webflow, Framer, WordPress, and CMS sites use platform adapters.

2. Connect once

Keep secrets server-side

Store tenant publish tokens, GitHub App grants, or CMS credentials only in CI or encrypted server-side storage.

3. Publish daily

Let the host serve pages

The tenant website remains canonical and owns rendering, sitemap, internal links, analytics, theme, and CDN delivery.

Agent setup

Let a coding agent wire the tenant repo

The tenant integration skill tells an agent to detect the real platform, route, content source, sitemap, deploy behavior, asset path, and safest Wotaso adapter before it changes any files.

npx skills add Wotaso/seodrafts-agent-skills --skill seo-blog-admin-projects --agent universal --yes

Or let any agent read the public raw skill directly without installing it.

Recommended architecture

Use the host's strongest publishing surface

The best SEO result is not a separate Wotaso-hosted blog. The best result is a crawlable page on the tenant's own domain, using the platform that already controls templates, internal links, sitemap, analytics, and CDN delivery.

Git-backed frameworks

GitHub App PR, static publisher fallback

Best for Next.js, Astro, Nuxt, SvelteKit, Remix, Eleventy, Hugo, Gatsby, Docusaurus, VitePress, and Markdown/MDX blogs. The smooth SaaS version is a GitHub App that opens a setup PR. The production-ready path today is the static publisher.

  • Daily behavior: commit approved posts and assets, then let Vercel, Netlify, Coolify, or the host rebuild.
  • Sitemap: automatic when the sitemap reads the content directory; otherwise use the SDK server-side.
  • Secret: tenant publish token lives only in CI or server-side environment variables.

No-code CMS

CMS tenants need native CMS publishers

These tenants should not be asked to create GitHub Actions. Wotaso should map reviewed posts into the native CMS collection, publish the CMS item, and let the platform serve the canonical URL.

  • Webflow: create staged CMS items, publish item IDs, and publish the site when needed.
  • Framer: sync managed CMS collections; Server API is a beta path, so keep a plugin/export fallback.
  • Secret: OAuth grants or API credentials must be encrypted server-side.

CMS and headless CMS

Publish entries through tenant-run CLI adapters

WordPress, Webflow, Wix, Contentful, Sanity, Strapi, Ghost, Shopify, HubSpot, and custom CMS setups have tenant-run npx --yes @wotaso/seo-blog-admin-cli@0.2.2 publish-cms paths. Framer's Server API path is beta. Validate the selected tenant schema and the resulting public route before enabling scheduled writes; trigger a host build hook only for static frontends.

  • Direct CMS: WordPress, Ghost, Shopify, and HubSpot serve canonical posts after API publish.
  • Headless CMS: Contentful, Sanity, and Strapi field mapping must match the frontend schema and locale model.
  • Deploy hooks: use Vercel, Netlify, or Coolify hooks only after a CMS entry changes.

Avoid by default

Hosted proxy pages are a last resort

A Wotaso-hosted proxy or subdomain splits authority, internal links, analytics, conversion tracking, and UX from the tenant site. Use it only as a temporary demo when no canonical host integration is possible.

  • Preferred: tenant domain, tenant templates, tenant sitemap.
  • Fallback: authenticated webhook into a tenant-owned publisher.
  • Never: doorway pages, hidden content, fake reviews, or automated spam backlinks.

Current production path for Git-backed sites

Static publisher for fast SEO pages

Most SaaS and docs websites with a repository can use the static publisher now. It writes reviewed content into the host repository as Markdown or MDX, so the final page is built by the website itself.

  • Performance: pages are rendered by the host framework and served by the existing CDN.
  • SEO: crawlers receive normal HTML, canonical URLs, internal links, and visible FAQ content.
  • Safety: only approved due posts are pulled, and existing files are not overwritten by default.

Run once in the website repository

npx --yes @wotaso/seo-blog-admin-cli@0.2.2 init-static \
  --site-slug flashes \
  --site-origin https://flashes.app \
  --content-dir apps/website/src/content/blog \
  --extension mdx

Then set the GitHub secret from the CLI

npx --yes @wotaso/seo-blog-admin-cli@0.2.2 login-password \
  --api-url https://api.seodrafts.com \
  --email owner@example.com \
  --password-stdin

npx --yes @wotaso/seo-blog-admin-cli@0.2.2 rotate-token flashes \
  --repo owner/repository

The CLI rotates a tenant-scoped publish token and writes it to the repository secret named SEO_BLOG_PUBLISH_TOKEN. Without --repo, it prints the token once for other CI or server-side secret stores.

What the setup creates

seo-blog.config.json

{
  "apiUrl": "https://api.seodrafts.com",
  "siteSlug": "flashes",
  "siteOrigin": "https://flashes.app",
  "contentDir": "apps/website/src/content/blog",
  "basePath": "/blog",
  "extension": "mdx",
  "format": "astro",
  "frontmatterPreset": "astro-basic",
  "faqRender": "details",
  "assetDir": "apps/website/public/seo-assets",
  "assetPublicBaseUrl": "https://flashes.app/seo-assets",
  "limit": 10,
  "publishTokenEnv": "SEO_BLOG_PUBLISH_TOKEN"
}

How daily publishing works

  1. 1. Review: approve content in Wotaso when it is ready.
  2. 2. Schedule: approved posts become due according to the tenant schedule.
  3. 3. Pull: the GitHub Action runs daily and pulls due posts with the tenant token.
  4. 4. Commit: new Markdown/MDX files and generated assets are committed to the website repository.
  5. 5. Deploy: the normal host deploy rebuilds the site and serves the pages from its CDN.

If your host deploys on every commit, no custom redeploy API is needed. If your host does not, trigger your normal deploy step after the publisher commit.

Native CMS paths

CMS tenants can publish without repo changes

Nine stable tenant-run adapters cover Webflow, Wix, WordPress, Contentful, Sanity, Strapi, Ghost, Shopify, and HubSpot. Framer's Server API adapter is a beta path, while custom CMS sites can select the generic webhook connector separately. Each path runs through publish-cms in the tenant's CI or server environment with provider credentials stored as secrets.

Exercise the selected adapter against the tenant's real field model and review its first public canonical route before enabling scheduled writes. A fully hosted SaaS OAuth connection flow still needs encrypted credential storage before Wotaso can safely hold provider credentials centrally.

No-code and direct CMS

The adapters are designed to create or update native collection items, posts, or articles. Confirm the platform's publish result, rendered metadata, and public canonical route in the tenant account before treating the integration as live.

Headless CMS

Contentful, Sanity, and Strapi support tenant-run entry writes. Field mappings, locale behavior, and frontend rendering remain tenant-specific; static frontends should call their build hook after a confirmed CMS write and then verify the public route.

Generic webhook

Custom publishers receive a signed payload with Markdown, HTML, metadata, FAQ, visuals, and canonical URL context. They must return the final published URL before Wotaso marks the post as published.

CMS CLI publisher

One command shape for nine stable CMS targets, plus Framer beta

Always begin with --dry-run. It reads approved due posts and builds a no-write payload and field-mapping preview, but it does not call the CMS provider, validate credentials or schema remotely, publish a page, or prove that a public canonical route exists. If no post is due, provider-specific preview work might not run. Remove --dry-run only after review; then verify the first rendered route before enabling the scheduled runner.

SEO_BLOG_PUBLISH_TOKEN=<tenant-token> \
SEO_BLOG_SITE_SLUG=flashes \
WEBFLOW_TOKEN=<webflow-token> \
WEBFLOW_COLLECTION_ID=<collection-id> \
npx --yes @wotaso/seo-blog-admin-cli@0.2.2 publish-cms \
  --cms webflow \
  --site-slug flashes \
  --site-origin https://flashes.app \
  --field-map 'post-body=bodyHtml,meta-title=metaTitle,meta-description=metaDescription' \
  --dry-run
WordPress: WORDPRESS_URL, WORDPRESS_USERNAME, WORDPRESS_APP_PASSWORD
Webflow: WEBFLOW_TOKEN, WEBFLOW_COLLECTION_ID, --field-map
Framer (beta): FRAMER_API_KEY, FRAMER_PROJECT_URL, FRAMER_COLLECTION
Wix: WIX_API_KEY, WIX_SITE_ID, WIX_MEMBER_ID
Contentful: CONTENTFUL_MANAGEMENT_TOKEN, CONTENTFUL_SPACE_ID, CONTENTFUL_CONTENT_TYPE
Sanity: SANITY_TOKEN, SANITY_PROJECT_ID, SANITY_DATASET
Strapi: STRAPI_URL, STRAPI_TOKEN, STRAPI_COLLECTION
Ghost: GHOST_ADMIN_URL, GHOST_ADMIN_API_KEY
Shopify: SHOPIFY_SHOP, SHOPIFY_ADMIN_TOKEN, SHOPIFY_BLOG_ID
HubSpot: HUBSPOT_PRIVATE_APP_TOKEN, HUBSPOT_CONTENT_GROUP_ID, HUBSPOT_AUTHOR_ID
Webhook: WEBHOOK_URL, optional WEBHOOK_SECRET

Squarespace uses a reviewed manual handoff

There is no native Squarespace publisher command in this flow. Hand the approved Markdown or HTML to a human editor, create or update the draft in the tenant's normal Squarespace session, and verify the rendered route, metadata, assets, and canonical URL before recording completion. Do not request a Squarespace password or show an optional Squarespace webhook command. If the tenant already owns an authenticated custom publisher, select the generic webhook connector separately and document it as that connector.

Scheduled-runner health heartbeat

Run this from the real CMS cron or server runner after seo-blog.config.json contains the matching site identity and cms.provider. Keep the publish token and provider credential in that runner's secret store.

{
  "apiUrl": "https://api.seodrafts.com",
  "siteSlug": "flashes",
  "siteOrigin": "https://flashes.app",
  "publishTokenEnv": "SEO_BLOG_PUBLISH_TOKEN",
  "cms": { "provider": "webflow" }
}
SEO_BLOG_PUBLISH_TOKEN=<tenant-token> \
SEO_BLOG_SCHEDULED=true \
WEBFLOW_TOKEN=<webflow-token> \
npx --yes @wotaso/seo-blog-admin-cli@0.2.2 health \
  --config seo-blog.config.json \
  --mode cms \
  --site-slug flashes \
  --site-origin https://flashes.app

The heartbeat checks the runner's config, site identity, declared schedule, publish token, and presence of the configured provider secret; it does not validate the provider credential remotely or prove that a page is live. Ready status is temporary: use the server-provided publisherHealthNextExpectedAt deadline, or treat a heartbeat older than 36 hours as stale when no deadline is available.

Sitemap, FAQ, images, and themes

Sitemap

If your sitemap reads the blog content folder at build time, new posts appear automatically after the daily commit and redeploy. If your sitemap is custom, merge published URLs with the SDK on the server or during build.

FAQ rendering

The default output uses crawlable HTML <details> blocks. Host projects can style classes such as seo-blog-faq and seo-blog-faq__item without changing the content pipeline.

Generated images

Data image assets are rewritten into deterministic files under public/seo-assets by default. Your host then serves them through the same static asset layer or CDN as the rest of the site.

Theme control

Wotaso does not force a blog UI. Your website decides typography, author boxes, CTA blocks, related posts, colors, and layout.

Tenant FAQ

Does Wotaso host my canonical blog?

No. Your website remains canonical. Wotaso stores draft, approval, schedule, and publishing state; your website renders the final pages.

Does the publish token go into the mobile app or browser?

No. The publish token belongs only in a server-side environment or CI secret for the tenant website. It must not be bundled into an IPA, Android app, frontend JavaScript, or public repository.

How do new posts reach the website every day?

Git-backed websites can use a daily publisher job that commits Markdown or MDX files and assets. No-code and CMS websites should use native adapters that create or update CMS items and publish through the platform API.

Do we need to update the sitemap manually every day?

Usually no. Git-backed sites update the sitemap during the normal rebuild when the sitemap reads the content folder. Webflow, Framer, WordPress, and CMS sites should rely on the platform sitemap or a server/build-time sitemap merge.

Do CMS tenants need GitHub Actions?

No. GitHub Actions are for Git-backed websites. CMS tenants should run a native CMS publisher that writes CMS items and lets the platform publish the canonical pages.

How do deploys refresh after a new post?

Git-backed sites redeploy from the daily commit. Webflow and Framer publish through their platform flow. WordPress serves the post after REST publishing. Headless CMS static sites should call the host build hook after the entry is published.

Can the same setup work for different themes?

Yes. Wotaso writes structured content, FAQ data, and stable class names. Each host project controls CSS and templates.

Who owns the sitemap and rendering?

The tenant website owns rendering, routes, canonical URLs, styling, deployment, and the sitemap. Wotaso supplies reviewed structured content and publishing state.

What about backlinks?

Wotaso can help plan legal link earning: useful assets, directory submissions, source pages, and reviewed outreach notes. It must not automate spam, paid link schemes, fake reviews, or manipulative link networks.