Bulk update AI-generated meta fields
Storyblok is the first headless CMS that works for developers & marketers alike.
Storyblok's AI SEO App uses LLMs to generate the content of HTML and Open Graph (OG) <meta>
tags to speed up the editorial process.
An invaluable SEO tool, the app scans a story's contents and helps editors generate matching meta fields with one click. While this works great for one-time tasks, there's currently no easy way to generate content programmatically or in bulk for all relevant stories.
The Node.js script presented in this tutorial solves this challenge using the Management API (MAPI).
You can find the code for this tutorial in a dedicated GitHub repository.
Once you configure and run the script, it will generate or update the predefined set of tags supported by the app using your preferred AI provider/model. This saves content editors even more time; they only need to check the output and revise where needed.
Setup and usage
The script processes all stories of a specific content type block that contain an AI SEO field. It uses a custom AI API request to generate optimized metadata, so make sure you have access to OpenAI, Anthropic, or another provider's API.
First, clone the accompanying repository and install the dependencies:
npm install
Then, rename .env.example
to .env
and provide the required credentials and variables:
# Storyblok details
SB_MANAGEMENT_API_TOKEN=your_token_here
SB_SPACE_ID=12345
# Storyblok schema
SB_CONTENT_TYPE_BLOCK=page
SB_AI_SEO_FIELD=sb_ai_seo
# AI API credentials
AI_API_URL=https://api.example.com
AI_API_TOKEN=your_ai_token_here
AI_CUSTOM_PROMPT="Your_prompt_here"
Where to find the required details in Storyblok:
- To generate a personal access token, open Spaces and select My account > Account settings. Select Personal access token and then Generate new token.
- To get your space ID, select the space you work on and open Settings > Space.
- To find the content type block, open the Block library, select the relevant block, select Config, and copy the Technical name.
- To find the AI SEO field, repeat these steps, select the relevant field, and copy the Field name.
Finally, run a test with the --dry-run
flag, then generate or update the SEO metadata of all relevant stories, and verify that all stories were updated successfully:
# Test (recommended first)
npm run update -- --dry-run
# Perform the update
npm run update
Command line arguments
You can override some values set as environment variables:
--space-id=VALUE
: override the pre-configured space ID--content-type-block=VALUE
: override the pre-configured content type block--ai-seo-field=VALUE
: override the pre-configured AI SEO field name
# Example command with overrides
npm run update -- --space-id=12345 --content-type-block=blog_post --ai-seo-field=seo_metadata
It's recommended to use a testing space with a sample set of stories to ensure everything works as expected before running the script in production.
What the tool does
The bulk update tool comprises two files: index.js
, which sets up the configuration, and bulk-update-ai-seo.js
, which contains the API calls. Together, these perform the following actions:
- Fetch all stories with a specified content type block using pagination
- Generate AI SEO meta tags for all matching stories in the space
- Skip system fields (starting with
_
), such as_uid
and_editable
, before updating - Preserve existing non-AI SEO field values
- Rate limit with a 1-second delay between requests to avoid API throttling
- Provide detailed progress and completion reports, and complete operation and error logs
Right now, the script updates all matching fields. Reach out to let us know if you would like an option to generate only empty fields.
The script generates content for specific tags while preserving existing values (or setting defaults) of non-AI fields:
Changed tags | Ignored tags |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
| |
| |
| |
|
Customize the script
You can adapt various aspects of the script to match your needs:
Define an AI prompt
In .env
, provide a value for AI_CUSTOM_PROMPT
and instruct the LLM what to consider when it generates the SEO content.
Adjust the MAPI's parameters
The script uses a single MAPI client (this.client
) for all operations. You can customize the following parameters:
- Region settings: uncomment and set the
region
parameter - Content filtering: modify the
filter_query
infetchStoriesByContentType
- Pagination size: adjust the
per_page
parameter for different batch sizes - Filter system fields: modify the
cleanContent
method to set different field filtering rules
// ...
// 1. Management API client for all operations
this.client = new StoryblokClient({
oauthToken: settings.token,
// region: 'us'
});
// ...
/**
* 2. Fetch stories with the specified content type block that have the AI SEO field
*/
async fetchStoriesByContentType(page = 1, per_page = 25) {
try {
const response = await this.client.get(
`spaces/${this.space_id}/stories`,
{
filter_query: {
component: { in: this.content_type_block },
},
page,
per_page,
story_only: true,
},
);
// ...
/**
* 3. Clean the content object by removing specific fields
*/
cleanContent(content) {
if (!content || typeof content !== 'object') {
return content;
}
const cleanedContent = {};
for (const [key, value] of Object.entries(content)) {
// Skip fields that start with an underscore (such as _uid, _editable, etc.)
if (key.startsWith('_')) {
continue;
}
// Include all other fields
cleanedContent[key] = value;
}
return cleanedContent;
}
// ...
Customize the AI API integration
Depending on the AI API you use, you may need to adapt the API call in the generateAiSeoContent
method:
- Request format: adjust the request
body
structure - Response parsing: modify how the AI
response
is parsed - Error handling: adapt error handling for your API's response format
// ...
// Make a request to the AI API. This is a generic structure for Anthropic models that you can adapt to other AI APIs
const aiResponse = await (
await fetch(this.ai_api_url, {
body: JSON.stringify({
max_tokens: 1000,
messages: [{ content: prompt, role: 'user' }],
model: 'claude-opus-4-20250514',
}),
headers: {
'anthropic-version': '2023-06-01',
'Content-Type': 'application/json',
'x-api-key': this.ai_api_token,
},
method: 'POST',
})
).json();
if (!aiResponse) {
throw new Error(
`AI API request failed: ${aiResponse.status} ${aiResponse.statusText}`,
);
}
// ...
Tweak the API calls as needed, and check the logs; the tool provides extensive reporting to inform and alert you to potential issues.
Takeaways
The Management API allows you to tap into the inner workings of Storyblok’s UI. And since this tool is a platform-agnostic Node.js script, you can adapt it to the frontend framework of your choice.
Experiment with different prompts and models, adjust the API calls, and modify the script to fit the requirments of your project and content team.
Alba Silvente Fuentes, Senior Frontend Engineer, created the tool as part of the Storyblok MAPI helpers. Discover more useful utilities in the MAPI helpers GitHub repository.
If you’ve already used the AI SEO App you know how much time it saves; now you can boost your content team’s joy and productivity, letting them focus on the stories they want to tell.