If you’ve ever wanted to fetch and display your Blogger posts inside a modern Next.js application, this tutorial will walk you through the entire process — from setting up your environment to fetching and displaying live posts.
Step 1: Create a New Next.js Project
Open your terminal and navigate to the folder where you want your project to live. Then run:
npx create-next-app@latest blogger-integration
This will create a new folder named blogger-integration with a fresh Next.js setup.
Step 2: Setup Environment Variables
Inside your project, create a file named .env.local and add the following variables:
NEXT_PUBLIC_BLOGGER_BLOG_ID=1234567890123456789
BLOGGER_API_KEY=AIza...your_api_key_here
These variables will store your Blogger Blog ID and Google API key securely.
Step 3: Enable Blogger API and Generate API Key
- Go to Google Cloud Console.
- Create a new project (or select an existing one).
- From the left sidebar, navigate to APIs & Services → Library.
- Search for Blogger API v3 and click Enable.
- Next, go to APIs & Services → Credentials.
- Click Create Credentials → API key.
- Restrict the key to Blogger API and click Create.
- Copy your new API key and paste it inside
.env.localasBLOGGER_API_KEY.
Step 4: Get Your Blogger Blog ID
- Open your Blogger dashboard.
- Choose your blog and check the URL — it will look like this:
https://www.blogger.com/blog/posts/{blog-id}
Copy the blog ID part and paste it into your .env.local file as NEXT_PUBLIC_BLOGGER_BLOG_ID.
Step 5: Create the API Route
Inside your project, create a file at:
app/api/blog/route.ts
Then paste this code:
import { NextResponse } from 'next/server';
const BLOG_ID = process.env.NEXT_PUBLIC_BLOGGER_BLOG_ID;
const API_KEY = process.env.BLOGGER_API_KEY;
export async function GET(request: Request) {
if (!BLOG_ID || !API_KEY) {
return NextResponse.json(
{ error: 'Missing BLOG_ID or API_KEY in environment' },
{ status: 500 }
);
}
const url = new URL(`https://www.googleapis.com/blogger/v3/blogs/${BLOG_ID}/posts`);
url.searchParams.set('key', API_KEY);
const incoming = new URL(request.url);
incoming.searchParams.forEach((value, name) => {
if (name === 'key') return;
url.searchParams.set(name, value);
});
try {
const res = await fetch(url.toString());
if (!res.ok) {
const text = await res.text();
return NextResponse.json({ error: 'Upstream error', details: text }, { status: res.status });
}
const data = await res.json();
return NextResponse.json(data);
} catch (err: any) {
return NextResponse.json({ error: 'Fetch failed', message: err.message || String(err) }, { status: 500 });
}
}
What this does:
- Reads your Blogger Blog ID and API key from environment variables.
- Calls the official Google Blogger API to fetch posts.
- Returns clean JSON data to your frontend.
Step 6: Display Posts on the Home Page
Now open app/page.tsx and replace its content with:
import React from 'react';
import PostList from '../components/PostList';
type Post = {
id: string;
title: string;
content?: string;
published?: string;
url?: string;
author?: { displayName?: string } | null;
};
async function fetchPosts() {
const baseUrl = process.env.NEXT_PUBLIC_BASE_URL ||
(process.env.VERCEL_URL ? `https://${process.env.VERCEL_URL}` : 'http://localhost:3000');
const res = await fetch(`${baseUrl}/api/blog?maxResults=10`, { cache: 'no-store' });
if (!res.ok) {
const text = await res.text();
throw new Error(`Failed to fetch posts: ${res.status} ${text}`);
}
const data = await res.json();
return data.items ?? [];
}
export default async function Page() {
let posts: Post[] = [];
try {
posts = await fetchPosts();
} catch (e: any) {
console.error('Error fetching posts', e);
}
return (
<main className="p-6 max-w-3xl mx-auto">
<h1 className="text-3xl font-bold mb-4">My Blogger Posts</h1>
{posts.length === 0 ? (
<p>No posts found or failed to load.</p>
) : (
<PostList posts={posts} />
)}
</main>
);
}
This dynamically fetches your posts from the API route and passes them to a PostList component for display.
Step 7: Create the PostList Component
Make a new file:
components/PostList.tsx
Paste this code:
'use client';
import React from 'react';
type Post = {
id: string;
title: string;
content?: string;
published?: string;
url?: string;
author?: { displayName?: string } | null;
};
export default function PostList({ posts }: { posts: Post[] }) {
return (
<div className="space-y-6">
{posts.map((p) => (
<article key={p.id} className="border rounded-lg p-4 shadow-sm">
<a href={p.url} target="_blank" rel="noopener noreferrer">
<h2 className="text-xl font-semibold">{p.title}</h2>
</a>
<p className="text-sm text-gray-500">
{p.author?.displayName} — {p.published ? new Date(p.published).toLocaleString() : ''}
</p>
<div className="mt-2 prose max-w-none" dangerouslySetInnerHTML={{ __html: p.content ?? '' }} />
</article>
))}
</div>
);
}
This component:
- Loops through posts and displays them nicely using Tailwind CSS.
- Renders each post’s title, author, date, and content.
- Uses
dangerouslySetInnerHTMLto safely show Blogger’s HTML-formatted content.
Step 8: Optional — Client-side Example Page
Create a file:
app/client-example/page.tsx
Add this:
'use client';
import React, { useEffect, useState } from 'react';
export default function ClientExample() {
const [posts, setPosts] = useState<any[]>([]);
const [loading, setLoading] = useState(false);
const [err, setErr] = useState<string | null>(null);
useEffect(() => {
setLoading(true);
fetch('/api/blog?maxResults=5')
.then((r) => {
if (!r.ok) throw new Error(`Status ${r.status}`);
return r.json();
})
.then((data) => setPosts(data.items ?? []))
.catch((e) => setErr(String(e)))
.finally(() => setLoading(false));
}, []);
if (loading) return <p>Loading...</p>;
if (err) return <p>Error: {err}</p>;
return (
<div className="p-4">
<h2 className="text-2xl mb-3">Client-side posts</h2>
{posts.map((p) => (
<div key={p.id} className="mb-4">
<a href={p.url} target="_blank" rel="noreferrer">
<h3 className="font-medium">{p.title}</h3>
</a>
</div>
))}
</div>
);
}
This shows how to fetch and render posts client-side using React hooks.
Step 9: Run the Application
Now it’s time to test everything!
Run the development server:
npm run dev
Then open your browser and visit:
http://localhost:3000
You should now see all your Blogger posts fetched and displayed dynamically inside your Next.js app!
Final Thoughts
In this guide, you learned how to:
- Create a Next.js project
- Setup Blogger API access
- Securely use environment variables
- Build API routes to connect with Google Blogger
- Fetch and render posts both server-side and client-side
With this setup, you can easily extend your app to:
- Add pagination
- Filter or search posts
- Style your posts using Tailwind
- Deploy to Vercel for instant live hosting
