Contentstack integration for Nuxt
npm install nuxt-contentstack[![npm version][npm-version-src]][npm-version-href]
[![npm downloads][npm-downloads-src]][npm-downloads-href]
[![License][license-src]][license-href]
[![Nuxt][nuxt-src]][nuxt-href]
Contentstack integration for Nuxt.
- ✨ Release Notes
- 🏀 Online playground
- 📖 Documentation
> Notice: This is an OSS project by @timbenniks and _not_ an officially maintained package by the Contentstack team. Support requests can come through Github issues and via direct channels to @timbenniks.
This module requires:
- Nuxt 3.20.1 or higher (including Nuxt 4.x)
- @nuxt/image ^2.0.0 (required for image provider functionality)
Make sure to install these dependencies in your project:
``bash`
npm install nuxt@^3.20.1 @nuxt/image@^2.0.0or
pnpm add nuxt@^3.20.1 @nuxt/image@^2.0.0or
yarn add nuxt@^3.20.1 @nuxt/image@^2.0.0
- Complete set of Vue composables (entries, assets, by URL)
- Advanced filtering, pagination, and sorting
- Live Preview & Visual Builder support
- Personalization support with server-side middleware
- Image transformations with useImageTransform composable
- @nuxt/image integration with automatic optimization
- TypeScript support with full type safety
- Exposed SDKs: Delivery SDK, Live Preview Utils SDK, Personalize SDK
`bash`
npx nuxi module add nuxt-contentstack
`ts
// nuxt.config.ts
export default defineNuxtConfig({
modules: ["nuxt-contentstack"],
"nuxt-contentstack": {
// Required
apiKey: "your_contentstack_api_key",
deliveryToken: "your_delivery_token",
environment: "your_environment",
// Optional
region: "eu", // 'us' | 'eu' | 'au' | 'azure-na' | 'azure-eu' | 'gcp-na' | 'gcp-eu'
branch: "main",
locale: "en-us",
// Live Preview
livePreview: {
enable: true,
previewToken: "your_preview_token",
editableTags: true,
editButton: true, // or object with enable, position, exclude, includeByQueryParameter
mode: "builder", // 'builder' | 'preview'
ssr: false,
},
// Personalization
personalization: {
enable: true,
projectUid: "your_project_uid",
},
debug: true,
},
});
`
| Option | Type | Required | Default | Description |
| --------------- | --------- | -------- | --------- | ---------------------------------------------- |
| apiKey | string | Yes | - | Contentstack stack API key (starts with "blt") |deliveryToken
| | string | Yes | - | Delivery token (starts with "cs") |environment
| | string | Yes | - | Target environment ('preview' \| 'production') |region
| | string | No | 'us' | Contentstack region |branch
| | string | No | 'main' | Content branch |locale
| | string | No | 'en-us' | Default locale |debug
| | boolean | No | false | Enable debug logging |
| Option | Type | Default | Description |
| -------------- | ------------------------ | ----------- | ------------------------------------- |
| enable | boolean | false | Enable live preview |previewToken
| | string | - | Preview token (required if enabled) |editableTags
| | boolean | false | Add editable tags for visual building |editButton
| | boolean \| object | false | Enable/edit button config |mode
| | 'builder' \| 'preview' | 'builder' | Live preview mode |ssr
| | boolean | false | Enable SSR mode (experimental) |
Edit button object:
`ts`
editButton: {
enable: boolean
position?: 'top' | 'bottom' | 'left' | 'right' | 'top-left' | 'top-right' | 'top-center' | 'bottom-left' | 'bottom-right' | 'bottom-center'
exclude?: ('insideLivePreviewPortal' | 'outsideLivePreviewPortal')[]
includeByQueryParameter?: boolean
}
| Option | Type | Required | Description |
| ------------ | --------- | -------- | --------------------------- |
| enable | boolean | Yes | Enable personalization |projectUid
| | string | Yes | Personalization project UID |
Access via useNuxtApp().$contentstack:
`ts`
const {
stack, // Delivery SDK Stack instance
ContentstackLivePreview, // Live Preview Utils SDK
Personalize, // Personalize SDK
livePreviewEnabled, // boolean
editableTags, // boolean
variantAlias, // Variant manifest for personalization
VB_EmptyBlockParentClass, // Visual Builder empty block class
} = useNuxtApp().$contentstack;
`ts
const { Personalize } = useNuxtApp().$contentstack;
// Set user attributes
await Personalize.set({ age: 20 });
// Trigger impression
await Personalize.triggerImpression(experienceShortId);
// Trigger conversion event
await Personalize.triggerEvent("eventKey");
`
All composables support live preview updates, personalization variants, and Nuxt's caching system.
Fetch entry by URL field.
`ts`
const { data, status, refresh } = await useGetEntryByUrl
contentTypeUid: "page",
url: "/about",
referenceFieldPath: ["author", "category"],
jsonRtePath: ["rich_text_field"],
locale: "en-us",
replaceHtmlCslp: true,
});
Fetch single entry by UID.
`ts`
const { data } = await useGetEntry
contentTypeUid: "article",
entryUid: "your_entry_uid",
referenceFieldPath: ["author"],
jsonRtePath: ["content"],
locale: "en-us",
});
Fetch multiple entries with filtering, pagination, and sorting.
`ts
const { data } = await useGetEntries
contentTypeUid: "article",
referenceFieldPath: ["author"],
locale: "en-us",
limit: 10,
skip: 0,
orderBy: "created_at",
includeCount: true,
where: {
status: "published",
view_count: { $gt: 1000 },
created_at: { $gte: "2024-01-01", $lt: "2024-12-31" },
featured_image: { $exists: true },
title: { $regex: "nuxt.*contentstack" },
tags: ["tech", "news"],
author: { $ne: "guest" },
},
});
// Access results
console.log(data.value?.entries); // Article[]
console.log(data.value?.count); // number (if includeCount: true)
`
Fetch single asset by UID.
`ts`
const { data } = await useGetAsset
assetUid: "your_asset_uid",
locale: "en-us",
});
Fetch multiple assets with filtering.
`ts`
const { data } = await useGetAssets
locale: "en-us",
limit: 20,
orderBy: "created_at",
includeCount: true,
where: {
content_type: "image/jpeg",
// Note: Most asset filters are applied client-side
},
});
Supported in where clause for entry composables:
- Exact match: field: "value"tags: ["tech", "news"]
- Array contains: field: { $gt: 100, $gte: 50, $lt: 200, $lte: 150, $ne: "value" }
- Comparison: field: { $exists: true }
- Existence: field: { $regex: "pattern" }
- Regex:
Transform Contentstack images programmatically.
`ts
const { transformedUrl, updateTransform, resetTransform } = useImageTransform(
imageUrl,
{
width: 800,
height: 600,
quality: 80,
format: "webp",
fit: "crop",
blur: 5,
saturation: 10,
brightness: 5,
overlay: {
relativeURL: "/watermark.png",
align: "bottom-right",
width: "20p",
},
sharpen: {
amount: 5,
radius: 2,
threshold: 0,
},
}
);
// Update reactively
updateTransform({ width: 1200, quality: 90 });
`
Renders Contentstack modular blocks as Vue components with optional auto-fetch capability. Auto-fetch is disabled by default. To enable auto-fetch, provide both contentTypeUid and url props. When using pre-fetched blocks, pass blocks via the blocks prop without providing contentTypeUid or url.
Pattern 1: Auto-fetch Entry
`vue
:url="$route.path"
blocks-field-path="components"
:reference-field-path="['author']"
:json-rte-path="['rich_text']"
:auto-seo-meta="true"
:component-map="componentMapping"
>
Loading...
Failed to load
No content
`
Pattern 2: Pre-fetched Blocks
`vue
:component-map="componentMapping"
/>
`
| Prop | Type | Default | Description |
| ---------------------- | ----------------------------------- | -------------------------------------- | ---------------------------------------------------------- |
| blocks | ContentstackBlock[] | [] | Array of modular blocks |componentMap
| | ComponentMapping | {} | Block type → Vue component mapping |fallbackComponent
| | Component | ContentstackFallbackBlock | Component for unmapped blocks |contentTypeUid
| | string | undefined | Content type for auto-fetch (required if using auto-fetch) |url
| | string | undefined | URL for auto-fetch (required if using auto-fetch) |blocksFieldPath
| | string | 'components' | Field path to extract blocks |referenceFieldPath
| | string[] | [] | Reference fields to include |jsonRtePath
| | string[] | [] | JSON RTE field paths |locale
| | string | 'en-us' | Locale |replaceHtmlCslp
| | boolean | editableTags | Replace HTML CSLP tags |seoMeta
| | SeoMetaInput | - | SEO metadata (passed to useSeoMeta) |autoSeoMeta
| | boolean \| Record | false | Auto-generate SEO from entry |containerClass
| | string | 'contentstack-modular-blocks' | Container CSS class |emptyBlockClass
| | string | 'visual-builder__empty-block-parent' | Empty block CSS class |showEmptyState
| | boolean | true | Show empty state |keyField
| | string | '_metadata.uid' | Key field for blocks |autoExtractBlockName
| | boolean | true | Auto-extract block name |
Manual SEO:
`vue`
title: 'Page Title',
description: 'Page description',
ogImage: 'https://example.com/image.jpg',
}"
/>
Auto-generate SEO:
`vue
title: 'seo_title|title|name',
description: 'meta_description|description',
ogImage: 'featured_image.url',
}"
/>
`
Default auto-SEO mapping:
- title: seo_title → title → namedescription
- : seo_description → description → summaryogImage
- : featured_image.url → og_image.url → image.url
- loading - Custom loading state (auto-fetch mode)error
- - Custom error state (auto-fetch mode)empty
- - Custom empty state
Built-in fallback component for unmapped block types. Displays block title, type badge, and props as formatted JSON.
> Note: This module requires @nuxt/image version 2.0.0 or higher. Make sure you have it installed before using the Contentstack image provider.
The @nuxt/image module should already be installed as a peer dependency. If not, install it:
`bash`
npm install @nuxt/image@^2.0.0
`ts
// nuxt.config.ts
export default defineNuxtConfig({
modules: ["nuxt-contentstack", "@nuxt/image"],
image: {
providers: {
contentstack: {
name: "contentstack",
provider:
"node_modules/nuxt-contentstack/dist/runtime/providers/contentstack",
},
},
provider: "contentstack", // Optional: set as default
},
});
`
`vue
:alt="image.title"
width="800"
height="400"
:modifiers="{ auto: 'webp,compress', quality: 90 }"
provider="contentstack"
/>
sizes="100vw sm:50vw lg:33vw"
:modifiers="{ auto: 'webp,compress' }"
/>
sizes="100vw md:50vw"
:modifiers="{ auto: 'webp,compress' }"
/>
`
- auto: 'webp' | 'webp,compress'quality
- : numberformat
- : 'webp' | 'png' | 'jpg' | 'jpeg' | 'gif' | 'auto'width
- , height, dpr: numberfit
- : 'bounds' | 'crop'blur
- , brightness, contrast, saturation: numbersharpen
- : { amount, radius, threshold }overlay
- : { relativeURL, align, repeat, width, height, pad }
`bashInstall dependencies
npm install
[npm-version-src]: https://img.shields.io/npm/v/nuxt-contentstack/latest.svg?style=flat&colorA=020420&colorB=00DC82
[npm-version-href]: https://npmjs.com/package/nuxt-contentstack
[npm-downloads-src]: https://img.shields.io/npm/dm/nuxt-contentstack.svg?style=flat&colorA=020420&colorB=00DC82
[npm-downloads-href]: https://npmjs.com/package/nuxt-contentstack
[license-src]: https://img.shields.io/npm/l/nuxt-contentstack.svg?style=flat&colorA=020420&colorB=00DC82
[license-href]: https://npmjs.com/package/nuxt-contentstack
[nuxt-src]: https://img.shields.io/badge/Nuxt-020420?logo=nuxt.js
[nuxt-href]: https://nuxt.com