Back to all posts

Hoe ik onze blogproductie volledig automatiseer

Hoe ik onze blogproductie volledig automatiseer

Ik ben Ming. Naast productontwerp bij vm0 beheer ik ook onze content, en dat bleek veel meer werk dan verwacht: workflow-ontwerp, illustraties, beeldproductie, CMS-werk, vertalingen. Zo krijg ik het stap voor stap voor elkaar.


Content is een van mijn taken hier

Het grootste deel van mijn dag bij vm0 verdeel ik tussen productontwerp en onze Next.js-codebase. Maar ook het beheer van onze content hoort erbij, en toen ik begon, zag ik pas hoeveel er bij een goed presterende blog komt kijken. Je hebt consistente output nodig, echte zoekwoordenanalyse, merkvaste visuals, goede metabeschrijvingen en vertalingen naar de vier talen die we ondersteunen.

Toen ik dit serieus ging doen, kostte elke post bijna een hele dag. Het schrijven zelf bleek maar een klein deel. De meeste tijd ging zitten in het productieproces eromheen: de juiste zoekwoorden vinden, cover art maken, velden goed invullen in het CMS, en alles opnieuw doen voor elke taalvariant.

Dus heb ik geleidelijk zoveel mogelijk van die pijplijn ondergebracht in Lucas, een AI-marketingagent die ik op Zero heb gebouwd rond mijn dagelijkse werk. Hij is geconfigureerd als "Marketing manager" en zijn scope is alles wat met marketing te maken heeft: blogproductie is nu het meest uitgewerkte onderdeel, en hij groeit verder naarmate ik meer skills en connectors toevoeg.

Op dit moment heeft Lucas toegang tot onze Strapi headless CMS, ons Ahrefs-account, onze team-Slack, onze webchat, een interne draw skill voor merkvaste illustraties, plus de standaard copywriting skill voor de schrijfmechaniek.

Hieronder laat ik zien hoe deze AI-blogautomatisering in de praktijk werkt: hoe Lucas een vage prompt omzet in onderwerp en zoekwoorden, een concept schrijft, een cover tekent, de tekst natuurlijk vertaalt en vier concepten in onze headless CMS plaatst. Daarna vertel ik hoe ik hier ben gekomen en wat ik bewust aan mensen overlaat (meestal nog steeds aan mijzelf).


Hoe ik Lucas gebruik: webapp en Slack

Ik werk vooral met Lucas via de webchat van vm0. Dat is de deep-work interface waar ik samen met hem outline, concepten, cover-iteraties en bewerkingen doorloop. Lange threads, veel context, het soort interactie dat onhandig is in een chatkanaal.

Lucas is ook gekoppeld aan onze team-Slack, als gedeeld startpunt. Ik stuur daar snelle prompts vanaf mijn telefoon, en de rest van het team kan hem ook pingen. Wie er ook aan de beurt is voor de blog, start een post op dezelfde manier. Dezelfde agent, dezelfde context op beide interfaces.


Hoe een typische prompt eruitziet

Mijn prompts aan Lucas zijn meestal kort. Maximaal drie zinnen. Een representatief voorbeeld:

Lucas, schrijf een tutorial over het houden van effectieve wekelijkse vergaderingen: behandel de structuur, veelgemaakte fouten en hoe je remote teams betrokken houdt. Tutorialstijl, SEO-vriendelijk, eindig met een CTA om Zero te gebruiken. Alleen conceptlink, niet publiceren.

Dat is de hele briefing. Eén bericht. Geen outline, geen zoekwoordenlijst, geen designbrief, geen lengte-eis. Lucas neemt het vanaf daar over.

Het heeft even geduurd voordat ik op dit format uitkwam. In het begin schreef ik veel langere briefings omdat ik dacht dat de agent alles expliciet nodig had, maar ik realiseerde me dat de meeste context in zijn vaste instructies en skills hoort, niet in elke prompt. De prompt is een trigger; de rest van de configuratie draagt het gewicht.


Hoe Lucas het onderwerp en de zoekwoorden analyseert

Lucas' eerste stap is structuur halen uit een vage prompt. Voor een verzoek als hierboven zien zijn werknotities er zo uit:

  • Onderwerp: effectieve wekelijkse vergaderingen houden
  • Format: tutorial → genummerde stappen, concrete voorbeelden, "doe dit"-taal
  • Impliciet publiek: teamleiders, remote managers, oprichters
  • Vereiste secties: vergaderstructuur, veelgemaakte fouten, remote betrokkenheid
  • CTA: lezers naar Zero leiden
  • Beperking: alleen concept-URL, niet publiceren

Daarna kiest hij het zoekwoord. Dit was het deel van contentmarketing waar ik het minste gevoel voor had, dus heb ik Lucas een routine gegeven die hij altijd doorloopt als ik hem om zoekwoordenwerk vraag. Het is geen skill die hij autonoom draait, gewoon een volgorde die ik hem toevertrouw:

  1. Kandidaten ophalen uit Ahrefs. Hij roept de Ahrefs API aan op de onderwerpzin en krijgt long-tail variaties terug met maandelijks zoekvolume, keyword difficulty (KD), parent topic en SERP-intentie.
  2. Filteren op moeilijkheid. Ik heb hem een harde regel gegeven: KD < 30. vm0 is een relatief nieuw domein met beperkte autoriteit, dus hoge KD-zoekwoorden najagen heeft voor ons nog geen zin. Long-tail wint in het begin.
  3. Kruisverwijzen met onze Strapi-index. Hij haalt alle gepubliceerde slugs uit ons CMS via de Strapi REST API en verwijdert elk zoekwoord dat we al behandelen. Geen kannibalisatie.
  4. Intentie matchen met productfit. De intentie van een zoekwoord moet passen bij onze use case library. "Hoe effectieve wekelijkse vergaderingen houden" → operations / teammanagement → past. "Beste ramen in Tokio" → past niet, ongeacht het volume.
  5. Eentje kiezen. Uit de gefilterde lijst kiest hij de optie met het hoogste volume en gebruikt die als ruggengraat van de post. Bijvoorbeeld: remote wekelijkse vergadering best practices.

Voor on-page SEO hanteert hij een simpele vuistregel: doelzoekwoord in de titel, in minstens één H2 en in de eerste 100 woorden. Synoniemen en verwante termen natuurlijk verweven. Interne links naar twee of drie gerelateerde posts waar het past. Daarna: natuurlijk schrijven, geen keyword stuffing.

De structuur van de post (zes of zeven H2's, een "Tip:"-callout onder elke stap, een CTA aan het einde) komt uit een tutorialtemplate die ik door voorbeelden heb opgebouwd.


Hoe de cover wordt getekend

De cover is het deel van de blogproductie waar ik het meest om geef, deels omdat ik ontwerper ben en deels omdat het is wat lezers zien voordat ze een woord lezen. Het is ook de Open Graph-afbeelding als posts gedeeld worden op X of LinkedIn, en het zorgt ervoor dat onze blogindex eruitziet als een publicatie in plaats van een muur van stockfoto's.

Stockfoto's waren geen optie voor de uitstraling die ik wilde, en illustraties per stuk laten maken zou de productiekosten per post onhaalbaar maken. Dus heb ik een Zero-skill gebouwd genaamd draw. Het is een Python-script van 200 regels dat vijf dingen doet:

  1. Neemt twee inputs: een metafoor (wat te schetsen) en een kleur (een vriendelijke naam plus een hex-waarde).
  2. Zet ze in een vast prompttemplate dat de rest van de compositie vastlegt: warme grijze achtergrond #eeeeee, aquarelvlak gecentreerd op het canvas in de gekozen kleur, handgetekende inkttekening erbovenop, vm0-logo op (25, 25) linksboven.
  3. Stuurt de samengestelde prompt naar fal.ai's nano-banana-pro-model op 16:9.
  4. Downloadt de PNG. Normaliseert bijna-witte pixels terug naar precies #eeeeee zodat de achtergrond nooit afwijkt. Vergroot naar 1600×900. Alpha-compositeert het transparante vm0-logo erbovenop.
  5. Uploadt het resultaat naar vm0's CDN en print de URL.

Een typische aanroep ziet er zo uit:

python draw.py \
  --metaphor "a tilted hourglass with sand draining into a small open notebook, a sparkle near the rim" \
  --color-name "dusty rose" \
  --color-hex "#e08b96" \
  --upload

Twee inputs en de rest van het merk blijft consistent. Ik kies meestal een kleur die past bij het thema van de post. Koraal of salie voor warmere tutorialachtige stukken, blauw of lavendel voor meer technische, mosterdgeel voor aankondigingen. Een paar terugkerende kleuren maken de blogindex langzaam tot een herkenbaar palet.

Wat ik met vallen en opstaan heb geleerd, is dat de kracht niet in het model zit, maar in het template. Als het model vrij mocht kiezen qua compositie, palet en layout, leek elke cover op een ander merk. Door die vast te zetten en alleen de metafoor te laten variëren, blijft de uitstraling post na post coherent.

Er is een zusterskill genaamd illustration voor spot art in het artikel (de kleinere tekeningen tussen de secties van deze post). Zelfde idee: vaste stijl, alleen metafoor en kleur variëren. Gewoon afgestemd op vierkante 1024×1024-art in plaats van 16:9-covers.

Een kleine opmerking over image SEO: dezelfde coverafbeelding wordt gebruikt als Open Graph- en Twitter Card-asset, zodat social shares hem netjes oppikken. Strapi genereert bij upload automatisch vier voorverkleinde varianten (thumbnail, small, medium, large), al heb ik het artikellichaam nog niet gekoppeld aan laden via srcset. Dat is een kleine front-end TODO. Inline illustraties krijgen beschrijvende alt-tekst in de markdown als Lucas ze insluit; de eigen alternativeText van de cover in Strapi wil ik nog aanvullen.


Hoe de post wordt geschreven

Als onderwerp, zoekwoord en cover vastliggen, is het schrijven vooral mechanisch. Lucas:

  1. Maakt eerst een outline. Zes of zeven H2's, elk met een duidelijke functie: probleemstelling, stapsgewijze instructies, "Tip:"-callouts, samenvatting, CTA.
  2. Breidt elke H2 uit tot proza met de copywriting-skill. De toon (korte zinnen, concrete voorbeelden, tweede persoon waar het past, af en toe droge humor) komt uit regels die ik in Lucas' vaste instructies houd, niet uit de skill zelf.
  3. Voegt praktische "Tip:"-callouts toe onder elke stap. Handig voor tutorials omdat de meeste lezers scannen, en de callouts geven ze een route door lange content.
  4. Schrijft het description-veld van de post. Strapi beperkt dit tot 80 tekens, dus het blijft kort en leest alsof een mens het schreef. Het wordt gebruikt als ondertitel en als OG/Twitter card-beschrijving.
  5. Eindigt met een CTA die het product noemt en linkt naar een gratis workspace.

Een eerste concept komt meestal twee à drie minuten na de prompt terug. Ik lees het, vraag om toonaanpassingen als de stem niet klopt, en Lucas past aan tot het goed is. Het eerste concept is zelden direct publiceerbaar. Het is meestal grotendeels goed, maar net niet helemaal, en daar besteed ik het meeste van mijn reviewtijd aan.


Hoe het concept in Strapi terechtkomt

We gebruiken Strapi als onze headless CMS. Het articles contenttype heeft een cover (media), author en category (relaties), locale (string), en een blocks dynamic zone waar de body staat.

Lucas' CMS-syncflow:

  1. POST de cover-PNG naar /api/upload. Sla de geretourneerde documentId op.
  2. POST naar /api/articles?status=draft met titel, beschrijving (≤80 tekens; Strapi handhaaft dit), slug, taalvariant, de cover/author/category-relaties als numerieke ID's, en één shared.rich-text-blok met de markdown-body.
  3. Belangrijk: laat publishedAt weg. Strapi behandelt null als conceptstatus.
  4. Retourneer een preview-URL volgens vm0's conceptpatroon: https://www.vm0.ai/{locale}/blog/posts/{slug}?status=draft.

Let op bij Strapi v5: de publieke REST API kan publishedAt overschrijven op bepaalde contenttypes, waardoor een "concept" dat je via de API aanmaakt ongemerkt live kan gaan. De oplossing is een kleine DB-migratie die het veld bij conceptwrites verwijdert.

De slugstrategie is ook belangrijk voor SEO. Wij gebruiken één canonieke slug voor alle vier de talen in plaats van deze te vertalen. Een lezer op /de/blog/posts/remote-weekly-meeting-best-practices ziet dezelfde URL-structuur als een lezer op /en, en ons backlinkprofiel versnipperd niet over vertaalde URLs. Het toevoegen van hreflang-linktags vanuit die taalrelaties is een kleine front-end TODO. Die leveren we nog niet mee.


Hoe i18n-vertaling werkt

vm0 ondersteunt vier talen: Engels, Duits, Japans, Spaans. We halen posts niet door Google Translate. De goedkope route sloopt de toon; de juiste route past uitdrukkingen aan.

Lucas maakt eerst het EN-concept, slaat de geretourneerde documentId op, en doet dan drie opvolgende PUT /api/articles/{documentId}?locale=de- (en ?locale=ja-, ?locale=es-) calls met natuurlijk vertaalde payloads. Strapi behandelt die als taalvarianten van hetzelfde canonieke document, waardoor de vier versies gekoppeld blijven in de admin en op de front-end taalwisselaar.

Vertaalregels die ik hem heb meegegeven, vooral na verkeerde uitkomsten corrigeren:

  • Vertaal geen technische termen die al Engelse leenwoorden zijn in de doeltaal. "API", "CMS", "agent" en "prompt" blijven in het Engels in JA en DE. Vertalen voelt in beide talen onnatuurlijk.
  • Pas uitdrukkingen natuurlijk aan. Een letterlijke vertaling van "kills your Friday" naar het Duits is onzin; een native versie van dezelfde metafoor werkt wel.
  • Stem CTA's af per taal. Gebiedende wijs klinkt dwingender in DE, dus die verzacht ik; de JA-versie wordt meestal een beleefde uitnodiging.
  • Pas titels aan qua lengte. Duitse titels zijn gemiddeld ~30% langer dan Engelse. Japanse titels zijn meestal korter. Lucas houdt titels per taal onder de 60-tekens SERP-afkaplimiet.

Meertalige contentpublicatie was het deel van de workflow dat het meeste tijd kostte. Nu is het gewoon de laatste stap in dezelfde agent-run.


Wat niet wordt geautomatiseerd

Een kort, belangrijk onderdeel. Niet alles in deze workflow is bewust geautomatiseerd:

  • Onderwerpkeuze op strategisch niveau. Lucas kiest zoekwoorden binnen een onderwerp, maar het onderwerp zelf komt van mij, meestal uit productlanceringen, klantgesprekken of roadmapwijzigingen.
  • Laatste redactionele check. Ik lees elk concept voordat het live gaat. Vooral de EN-versie. Toon, technische juistheid, verwijzingen naar interne productcontext moeten door een mens worden gecontroleerd.
  • Native review voor talen die ik niet vloeiend spreek. Ik lees geen vloeiend Duits. Het DE-concept gaat naar een native reviewer voor een laatste check voor publicatie.
  • Promotie. Posten op X, versturen naar abonnees, delen in communities gebeurt voorlopig nog handmatig.

Het doel is niet om mezelf uit de loop te halen. Het is om mezelf uit de delen van de loop te halen waar ik niet echt nodig ben.


Hoe ik tot deze workflow kwam

Ik heb dit niet in één weekend ontworpen. Het is gegroeid, post na post, door te zien welke stappen mijn tijd opslokten.

Wat ik merkte: de stappen die het waard waren om te automatiseren, waren niet de creatieve. Het waren de verbindende: de zoekwoordpulls, de coverrenders, de uploadcalls, de taaluitrol, de preview-URL-formattering. Eerlijk geteld besteedde ik meer tijd aan logistiek dan aan het eigenlijke schrijven.

Dus heb ik de logistiek geleidelijk in de agent ondergebracht. Het model schrijft; de agent regelt het verplaatsen van onderdelen. Ik bepaal nog steeds wat er geschreven wordt en hoe het klinkt, maar ik hoef niet meer alles aan elkaar te naaien.

Voor mij is contentautomatisering in de praktijk niet "de AI schrijft de blog" geworden. Het is geworden: "de AI doet alles rondom het schrijven, zodat ik tijd heb om echt naar het schrijven te kijken."


Als je iets soortgelijks wilt proberen

Sta je in een vergelijkbare situatie, met meer petten op dan je wilt en content als een van die taken, dan is het meeste hiervan reproduceerbaar:

  • Een agentplatform waarmee je de agent een vaste rol en skills kunt geven (wij gebruiken Zero, waar Lucas draait).
  • Connectors naar je bestaande tools: je CMS, je zoekwoordtool, je beeldgenerator, je Slack.
  • Een kleine set skills afgestemd op je merk (bij ons draw voor covers en copywriting voor toon).
  • Vaste instructies die context dragen, zodat prompts kort kunnen blijven.

Start een gratis Zero workspace →

Of als je liever eerst meer agent-workflows wilt zien voor je je aanmeldt, onze use case library bevat 19 kant-en-klare automatiseringen voor engineering, product, marketing en operations.

Wil je Lucas specifiek klonen: maak een agent aan, geef hem de rol Marketing manager, koppel Strapi (of je CMS) + Ahrefs + een beeldgeneratietool, voeg een draw-skill toe gebaseerd op die van jou, en een copywriting-skill die je merkstem vangt. De rest ontdekt hij vanaf je eerste prompt.

Stay in the loop

// Get the latest insights on AI teammates and collaboration.