Guide · Next.js
Add an Instagram feed to Next.js
Two good ways to put a live Instagram feed in a Next.js app: drop in the Simpleembed widget as a small client component, or fetch the public JSON API in a Server Component and render the posts with your own markup. Both auto-update as you post to Instagram.
1Get your feed ID
Create a free Simpleembed account, connect your Instagram Business or Creator account, and create a feed. On the Feeds page, open the Embed code dialog — the data-feed-idvalue in the snippet is your feed ID. You'll use it in both approaches below.
2Simplest: install the npm package
simpleembed-react ships the auto-resizing widget component and a typed data hook — TypeScript types included, App Router ready:
npm install simpleembed-reactimport { InstagramFeed } from "simpleembed-react";
<InstagramFeed feedId="YOUR_FEED_ID" />Prefer no extra dependency? Both manual options below do the same thing with copy-paste code.
3Manual option A: the widget as a React component
The standard embed snippet doesn't work as-is in JSX — React never executes <script> tags it renders. Inject the script in an effect instead; the widget handles layout, lightbox, and auto-resizing exactly like the plain-HTML embed:
"use client"; // Next.js App Router only — plain React apps can drop this line
import { useEffect, useRef } from "react";
export function InstagramFeed({ feedId }: { feedId: string }) {
const ref = useRef<HTMLDivElement>(null);
useEffect(() => {
const container = ref.current;
if (!container) return;
// Script tags in JSX don't execute — inject it imperatively instead.
const script = document.createElement("script");
script.src = "https://simpleembed.com/embed.js";
script.async = true;
script.dataset.feedId = feedId;
container.appendChild(script);
return () => {
container.replaceChildren(); // remove iframe + script on unmount
};
}, [feedId]);
return <div ref={ref} />;
}Then anywhere in your app:
<InstagramFeed feedId="YOUR_FEED_ID" />4Manual option B: a Server Component on the JSON API
For full control over markup and styling, skip the widget and fetch the feed's public JSON endpoint on the server. The response shape:
type FeedResponse = {
feed: { id: string; name: string; source: string };
posts: Array<{
id: string;
mediaType: "IMAGE" | "VIDEO" | "CAROUSEL_ALBUM";
caption: string | null;
permalink: string;
imageUrl: string;
timestamp: string;
childCount: number;
}>;
};Fetch it with incremental revalidation so new posts appear without a redeploy:
// app/components/instagram-grid.tsx — Next.js Server Component
export async function InstagramGrid({ feedId }: { feedId: string }) {
const res = await fetch(`https://simpleembed.com/api/feeds/${feedId}`, {
next: { revalidate: 300 }, // the API is CDN-cached ~5 min anyway
});
if (!res.ok) return null;
const { posts }: FeedResponse = await res.json();
return (
<div style={{ display: "grid", gridTemplateColumns: "repeat(3, 1fr)", gap: 8 }}>
{posts.map((post) => (
<a key={post.id} href={post.permalink} target="_blank" rel="noreferrer">
<img
src={post.imageUrl}
alt={post.caption ?? "Instagram post"}
loading="lazy"
style={{ width: "100%", aspectRatio: "1", objectFit: "cover" }}
/>
</a>
))}
</div>
);
}Always render images through the imageUrlthe API gives you — it proxies Instagram's CDN so images never expire. For an iframe-only variant and a client-side hook, see the full React documentation.
Customize it
If you use the widget, layout, post count, and styling all live in your Simpleembed dashboard — change a setting there and every embedded feed updates in place, with no code changes or redeploys. The JSON API route is the opposite trade: you own the markup, so customization happens in your components.
Frequently asked questions
- Should I use the widget component or the JSON API?
- Use the widget if you want zero design work — it ships a responsive grid, lightbox, and auto-resizing out of the box. Use the JSON API when the feed has to match your design system exactly; you get raw post data and build the markup yourself.
- Does this work with the Pages Router?
- Yes. The widget component is plain React and works in either router (drop the "use client" directive outside the App Router). The Server Component example is App Router-only — in the Pages Router, fetch the JSON API in getStaticProps or getServerSideProps instead.
- How quickly do new Instagram posts show up?
- Simpleembed syncs your Instagram account automatically and the API response is CDN-cached for about five minutes. The widget always shows the latest sync; the Server Component picks up new posts on the next revalidation, so with revalidate: 300 you are at most a few minutes behind — no redeploy needed.
- Can I use next/image with the API's imageUrl?
- Yes. imageUrl points at Simpleembed's image proxy (so images never expire, unlike hotlinked Instagram CDN URLs). Allow that host under images.remotePatterns in next.config.ts and pass imageUrl straight to next/image.
- How much does Simpleembed cost?
- One Instagram source and one feed are free forever, including API access. The $7/month plan unlocks unlimited feeds and sources.
Get your feed ID in about two minutes
Create a free Simpleembed account, connect your Instagram Business or Creator account, and copy your embed snippet. One source and one feed are free forever; $7/month unlocks unlimited feeds, sources, and views.
Start free