Documentation Index
Fetch the complete documentation index at: https://buttercms.com/docs/llms.txt
Use this file to discover all available pages before exploring further.
Fetching localized content via API
After enabling Localization, you will need to update all API calls to include the locale parameter. The locale parameter tells the ButterCMS API which localized version of your content to return.
API endpoint patterns
Single Page
https://api.buttercms.com/v2/pages/<page_type_slug>/<page_slug>/?locale=en&auth_token=your_api_token
Multiple Pages
https://api.buttercms.com/v2/pages/*/?locale=en&page=1&page_size=10&auth_token=your_api_token
Page Types
https://api.buttercms.com/v2/pages/<page_type>/?locale=en&page=1&page_size=10&auth_token=your_api_token
Collections
https://api.buttercms.com/v2/content/<collection>/?locale=en&page=1&page_size=10&auth_token=your_api_token
JavaScript / Node.js examples
Basic setup
import ButterCMS from "buttercms";
const butterCMSClient = ButterCMS("your_api_token");
Fetching a single Page
// Fetch page in a specific locale
const { data } = await butterCMSClient.page.retrieve(
"landing_page", // page type
"home", // page slug
{
locale: "es", // locale parameter
preview: 1 // optional: include draft content
}
);
const { fields } = data.data;
console.log(fields.headline); // Spanish headline
Fetching multiple Pages
// Fetch all pages of a type in Spanish
const response = await butterCMSClient.page.list("blog_posts", {
locale: "es",
page: 1,
page_size: 10,
order: "-published"
});
const pages = response.data.data;
pages.forEach(page => {
console.log(page.fields.title);
});
Fetching Collections
// Fetch collection items in French
const { data } = await butterCMSClient.content.retrieve(
["team_members", "testimonials"],
{
locale: "fr",
page: 1,
page_size: 20
}
);
const teamMembers = data.data.team_members;
const testimonials = data.data.testimonials;
Dynamic locale selection
// Function to fetch content based on user's locale
async function getLocalizedPage(pageType, slug, userLocale) {
const supportedLocales = ['en', 'es', 'fr', 'de'];
const locale = supportedLocales.includes(userLocale)
? userLocale
: 'en'; // fallback
try {
const response = await butterCMSClient.page.retrieve(pageType, slug, {
locale
});
return response.data.data;
} catch (error) {
// Fallback to default locale if content not found
if (error.response?.status === 404) {
const fallback = await butterCMSClient.page.retrieve(pageType, slug, {
locale: 'en'
});
return { ...fallback.data.data, _fallback: true };
}
throw error;
}
}
Python examples
Basic setup
from butter_cms import ButterCMS
client = ButterCMS('your_api_token')
Fetching a single Page
# Fetch page in Spanish
response = client.pages.get(
'landing_page',
'home',
params={'locale': 'es'}
)
page = response['data']
print(page['fields']['headline'])
Fetching multiple Pages
# Fetch all blog posts in German
response = client.pages.all(
'blog_posts',
params={
'locale': 'de',
'page': 1,
'page_size': 10
}
)
for page in response['data']:
print(page['fields']['title'])
Fetching Collections
# Fetch collections in French
response = client.content_fields.get(
['team_members', 'faqs'],
params={'locale': 'fr'}
)
team_members = response['data']['team_members']
faqs = response['data']['faqs']
PHP / Laravel examples
Controller setup
<?php
namespace App\Http\Controllers;
use ButterCMS\ButterCMS;
class LandingPageController extends Controller
{
private $client;
public function __construct() {
$this->client = new ButterCMS('your_api_token');
}
public function showPage(string $type, string $pageSlug, string $locale = 'en')
{
// Fetch page with locale parameter
$params = [
'locale' => $locale,
'preview' => 1
];
$page = $this->client->fetchPage($type, $pageSlug, $params);
return view('page', [
'fields' => $page->getFields(),
'locale' => $locale
]);
}
}
Fetching Collections
// Fetch navigation items in Spanish
$menuParams = [
'page' => '1',
'page_size' => '10',
'locale' => 'es-es',
'test' => 1
];
$menuCollection = $this->client->fetchContentFields(
['navigation_items'],
$menuParams
);
$menuItems = $menuCollection['navigation_items'];
Ruby / Rails examples
Basic setup
require 'buttercms-ruby'
ButterCMS::api_token = 'your_api_token'
Fetching a single Page
# Fetch page in Japanese
page = ButterCMS::Page.find('landing_page', 'home', {
locale: 'ja'
})
puts page['data']['fields']['headline']
Fetching Collections
# Fetch collection in Portuguese
content = ButterCMS::Content.fetch(['team_members'], {
locale: 'pt-br',
page: 1,
page_size: 10
})
team_members = content['data']['team_members']
cURL examples
Fetch single Page
curl -X GET "https://api.buttercms.com/v2/pages/landing_page/home/?locale=es&auth_token=YOUR_API_TOKEN"
Fetch multiple Pages
curl -X GET "https://api.buttercms.com/v2/pages/blog_posts/?locale=de&page=1&page_size=10&auth_token=YOUR_API_TOKEN"
Fetch Collections
curl -X GET "https://api.buttercms.com/v2/content/?keys=team_members,faqs&locale=fr&test=1&auth_token=YOUR_API_TOKEN"
Next.js App Router example
Dynamic locale routing
// app/[locale]/page/[slug]/page.tsx
import ButterCMS from 'buttercms';
const butter = ButterCMS(process.env.BUTTER_CMS_API_KEY);
interface PageProps {
params: {
locale: string;
slug: string;
};
}
export default async function Page({ params }: PageProps) {
const { locale, slug } = params;
const response = await butter.page.retrieve('*', slug, {
locale,
preview: process.env.NODE_ENV === 'development' ? 1 : 0,
});
const { fields } = response.data.data;
return (
<main>
<h1>{fields.headline}</h1>
<div dangerouslySetInnerHTML={{ __html: fields.body }} />
</main>
);
}
// Generate static paths for all locales
export async function generateStaticParams() {
const locales = ['en', 'es', 'fr', 'de'];
// Fetch all page slugs
const response = await butter.page.list('*', { page_size: 100 });
const pages = response.data.data;
// Generate params for each locale + page combination
return locales.flatMap(locale =>
pages.map(page => ({
locale,
slug: page.slug,
}))
);
}
Handling locale in frontend frameworks
Next.js internationalized routing
Configure next.config.js for locale support:
// next.config.js
module.exports = {
i18n: {
locales: ["en", "fr", "es", "de"],
defaultLocale: "en",
},
};
Then use the locale in your data fetching:
export const getStaticProps = async ({ locale }) => {
const { data } = await butterCMSClient.page.retrieve(
"landing_page",
"home",
{ locale }
);
return {
props: {
fields: data.data.fields,
},
};
};
Previewing localized content
Use the preview parameter to fetch unpublished (draft) content in a specific locale.
Preview mode
To preview unpublished localized content, include the preview parameter:
https://api.buttercms.com/v2/pages/<page_type>/<page_slug>/?locale=es&preview=1&auth_token=your_api_token
Setting up preview URLs
Configure locale-specific preview URLs in your frontend:
// Preview URL generator
function getPreviewUrl(pageSlug, locale) {
const baseUrl = process.env.PREVIEW_BASE_URL;
return `${baseUrl}/${locale}/${pageSlug}?preview=true`;
}
// Example: https://preview.example.com/es/homepage?preview=true
Handling missing locale content
When content doesn’t exist in a requested locale, you have several options:
Option 1: fallback to default locale
async function getPageWithFallback(pageType, slug, preferredLocale, defaultLocale = 'en') {
const butter = Butter('your-api-token');
try {
// Try preferred locale first
return await butter.page.retrieve(pageType, slug, { locale: preferredLocale });
} catch (error) {
if (error.response?.status === 404) {
// Fallback to default locale
const fallbackPage = await butter.page.retrieve(pageType, slug, { locale: defaultLocale });
return { ...fallbackPage, _fallbackUsed: true };
}
throw error;
}
}
Option 2: show locale not available message
function LocalizedContent({ locale }) {
const [content, setContent] = useState(null);
const [notAvailable, setNotAvailable] = useState(false);
useEffect(() => {
fetchContent(locale)
.then(setContent)
.catch(() => setNotAvailable(true));
}, [locale]);
if (notAvailable) {
return <div>This content is not yet available in {locale}.</div>;
}
return content ? <PageContent data={content} /> : <Loading />;
}
Option 3: redirect to available locale
// Next.js middleware example
export function middleware(request) {
const locale = request.nextUrl.locale;
const availableLocales = ['en', 'es', 'fr'];
if (!availableLocales.includes(locale)) {
return NextResponse.redirect(new URL('/en' + request.nextUrl.pathname, request.url));
}
}
For unpublishing and deleting localized content, see Publishing Localized Content.
Best practices
Error handling
Always handle cases where content might not exist in a requested locale:
async function fetchWithFallback(pageType, slug, locale, defaultLocale = 'en') {
try {
return await butter.page.retrieve(pageType, slug, { locale });
} catch (error) {
if (error.response?.status === 404 && locale !== defaultLocale) {
console.warn(`Content not found for locale ${locale}, falling back to ${defaultLocale}`);
return await butter.page.retrieve(pageType, slug, { locale: defaultLocale });
}
throw error;
}
}
Caching considerations
- Cache responses per locale
- Invalidate cache when content is updated
- Consider using ISR (Incremental Static Regeneration) in Next.js
export const revalidate = 60; // Revalidate every 60 seconds
- Use the
fields parameter to request only needed fields
- Implement pagination for large collections
- Pre-fetch content for common locale switches