Nuxt
@citedseo/nuxt gives your server routes the feed and your pages their head tags. Two small server routes, and two pages that read them.
Hand this to your coding agent
Read https://developer.citedseo.ai/llms-full.txt. My CitedSEO site ID is <YOUR_SITE_ID>. Install @citedseo/nuxt. Add pages/blog/index.vue and pages/blog/[slug].vue with the article's head tags and JSON-LD in this Nuxt app, reading my articles with that package. The feed needs no key. Use only the functions and addresses that file lists.
Install
Section titled “Install”npm install @citedseo/nuxtpnpm add @citedseo/nuxtyarn add @citedseo/nuxtbun add @citedseo/nuxtWhat you’ll add
Section titled “What you’ll add”- .env
Directoryserver
Directoryapi
Directoryarticles
- index.get.ts every article
- [slug].get.ts one article
- citedseo.post.ts the webhook
Directorypages
Directoryblog
- index.vue the index
- [slug].vue one article
-
Set your site ID.
.env CITEDSEO_SITE_ID=YOUR_SITE_ID -
Add the two routes.
server/api/articles/index.get.ts import { fetchArticles } from '@citedseo/nuxt';export default defineEventHandler(() => fetchArticles({ siteId: process.env.CITEDSEO_SITE_ID! }));server/api/articles/[slug].get.ts import { fetchArticle } from '@citedseo/nuxt';export default defineEventHandler(async (event) => {const article = await fetchArticle({siteId: process.env.CITEDSEO_SITE_ID!,slug: getRouterParam(event, 'slug')!,});if (!article) throw createError({ statusCode: 404, statusMessage: 'Article not found' });return article;}); -
Add the index.
pages/blog/index.vue <script setup lang="ts">const { data: articles } = await useFetch('/api/articles');</script><template><ul><li v-for="article in articles" :key="article.id"><NuxtLink :to="`/blog/${article.slug}`">{{ article.title }}</NuxtLink><p>{{ article.description }}</p></li></ul></template> -
Add the article page.
articleHeadgives the title, description, canonical link, Open Graph tags and JSON-LD in the shapeuseHeadtakes.pages/blog/[slug].vue <script setup lang="ts">import { articleHead } from '@citedseo/nuxt';const route = useRoute();const { data: article, error } = await useFetch(`/api/articles/${route.params.slug}`);if (error.value || !article.value) {throw createError({ statusCode: 404, statusMessage: 'Article not found', fatal: true });}useHead(articleHead(article.value));</script><template><article v-if="article"><h1>{{ article.title }}</h1><img v-if="article.cover" :src="article.cover.src" :alt="article.cover.alt" /><div v-html="article.html" /></article></template>
When you publish
Section titled “When you publish”Each request reads the manifest, which is cached for a minute, so a new article shows within a minute with no webhook.
If you prerender the blog or cache your pages, refresh from a server route. webhookHandler checks the signature for you:
import { webhookHandler } from '@citedseo/nuxt';
const handle = webhookHandler({ secret: process.env.CITEDSEO_WEBHOOK_SECRET!, onPost: async (post) => { // Clear your cache, start a build, or store post.data. },});
export default defineEventHandler((event) => handle(toWebRequest(event)));See Update the moment you publish.
Keep the address the same
Section titled “Keep the address the same”Each article’s url is where CitedSEO expects it to live, and its structured data and canonical address say so. If your blog isn’t at /blog, set the site’s blog path in the app’s settings to match your route. See SEO for your article pages.