Integration·Hugo·intermediate
Automated blog posts for Hugo
Automated blog posts for Hugo: write markdown drafts from Crontent webhooks and trigger a Hugo rebuild.
How-to: Integrate Crontent with Hugo. Official docs: Hugo. Shared API contract: Publishing API and SDK.
Verify Crontent, fetch the post, write a markdown draft under content/, and trigger a Hugo rebuild only after human review.
Field mapping
| Crontent field | Hugo frontmatter |
|---|---|
title | title |
seo_title | Custom seo_title param for <title> partial |
slug | Filename or slug in frontmatter |
excerpt | description or summary |
body_mdx | Body (convert MDX to MD if needed) |
body_html | Use with markup: html if you skip Markdown |
tags | tags array |
hero_image_url | featured_image param |
canonical_url | canonicalUrl param |
sources[] | sources YAML list in frontmatter |
Webhook handler
Deploy alongside Hugo or in CI. Example Node handler:
ts
import { Crontent } from "@crontent/sdk";
import { writeFile, mkdir } from "node:fs/promises";
import { execFile } from "node:child_process";
import { promisify } from "node:util";
import { join } from "node:path";
const exec = promisify(execFile);
const crontent = new Crontent({ apiKey: process.env.CRONTENT_API_KEY! });
export async function handleWebhook(req: Request) {
const rawBody = await req.text();
const valid = await crontent.webhooks.verify({
rawBody,
signature: req.headers.get("x-crontent-signature"),
timestamp: req.headers.get("x-crontent-timestamp"),
secret: process.env.CRONTENT_WEBHOOK_SECRET!,
});
if (!valid) return new Response("unauthorized", { status: 401 });
const { post_id } = JSON.parse(rawBody);
const post = await crontent.posts.get(post_id);
const dir = join(process.cwd(), "content/posts");
await mkdir(dir, { recursive: true });
const fm = `---
title: ${JSON.stringify(post.title)}
description: ${JSON.stringify(post.excerpt ?? "")}
date: ${JSON.stringify(post.ready_at ?? post.created_at)}
draft: true
tags: ${JSON.stringify(post.tags)}
featured_image: ${JSON.stringify(post.hero_image_url ?? "")}
---
`;
await writeFile(join(dir, `${post.slug}.md`), fm + "\n" + post.body_mdx);
await exec("hugo", ["--minify"], { cwd: process.cwd() });
return new Response("ok");
}Alternatively, commit new files via GitHub API and let Netlify or Cloudflare Pages rebuild. Set draft: true so Hugo excludes the post from production until you remove the flag.
Git-based workflow
- Webhook writes file to a branch or opens a PR.
- Review diff in GitHub.
- Merge and let your host run
hugo.
Use X-Crontent-Delivery as an idempotency key to avoid duplicate commits.
Backfill
Script posts.list with pagination and write any slug not present under content/posts/. Run once after initial setup.