Skip to content

Your Instagram feed.
Clean JSON or drop-in widget.

Token rotation, API maintenance, and Meta's next policy change stay on our side.

FeedFusion
FeedFusion
FeedFusion
FeedFusion
FeedFusion
FeedFusion

What's included

Everything you need.
Nothing you don't.

Full API access on every tier. No feature gating, no dashboard lock-in.

JSON API

Your feed as clean JSON. Fetch it in any framework, build your own component.

Drop-in widget

One script tag. Renders a styled feed with no configuration required.

Token rotation

Instagram access tokens rotate automatically. You never touch one.

Real-time sync

New posts appear within an hour of publishing. No manual refresh.

Multi-client dashboard

Manage feeds for all your client sites from a single login.

Built by a developer

Joana Parente uses FeedFusion on her own client sites. This is a tool she maintains and actively depends on.

Get started

Three lines of logic.
One API call. Your Instagram feed, anywhere.

Pick your framework. The output is the same JSON on every tab.

app/instagram-feed/page.tsx
import Image from "next/image";

type Post = {
  id: string;
  mediaUrl: string;
  thumbnailUrl: string | null;
  permalink: string;
  caption: string;
  mediaType: "IMAGE" | "VIDEO" | "CAROUSEL_ALBUM";
};

async function getFeed() {
  const res = await fetch(
    "https://api.feedfusion.dev/v1/feed/feed_abc123",
    {
      headers: { Authorization: "Bearer ff_live_abc123" },
      next: { revalidate: 3600 },
    }
  );
  if (!res.ok) throw new Error("Failed to fetch feed");
  return res.json() as Promise<{ data: Post[] }>;
}

export default async function InstagramFeed() {
  const { data: posts } = await getFeed();

  return (
    <section className="grid grid-cols-2 gap-4 sm:grid-cols-3 lg:grid-cols-4">
      {posts.map((post) => (
        <a
          key={post.id}
          href={post.permalink}
          target="_blank"
          rel="noopener noreferrer"
          className="group relative aspect-square overflow-hidden rounded-lg"
        >
          <Image
            src={post.thumbnailUrl ?? post.mediaUrl}
            alt={post.caption?.slice(0, 120) ?? "Instagram post"}
            fill
            className="object-cover transition-transform group-hover:scale-105"
            sizes="(max-width: 640px) 50vw, (max-width: 1024px) 33vw, 25vw"
          />
        </a>
      ))}
    </section>
  );
}
InstagramFeed.tsx
import { useEffect, useState } from "react";

type Post = {
  id: string;
  mediaUrl: string;
  thumbnailUrl: string | null;
  permalink: string;
  caption: string;
  mediaType: "IMAGE" | "VIDEO" | "CAROUSEL_ALBUM";
};

export function InstagramFeed({ feedId }: { feedId: string }) {
  const [posts, setPosts] = useState<Post[]>([]);

  useEffect(() => {
    fetch(`https://api.feedfusion.dev/v1/feed/${feedId}`, {
      headers: { Authorization: "Bearer ff_live_abc123" },
    })
      .then((res) => res.json())
      .then((data) => setPosts(data.data));
  }, [feedId]);

  return (
    <div
      style={{
        display: "grid",
        gridTemplateColumns: "repeat(auto-fill, minmax(200px, 1fr))",
        gap: "1rem",
      }}
    >
      {posts.map((post) => (
        <a key={post.id} href={post.permalink} target="_blank" rel="noopener noreferrer">
          <img
            src={post.thumbnailUrl ?? post.mediaUrl}
            alt={post.caption?.slice(0, 120) ?? "Instagram post"}
            style={{ width: "100%", aspectRatio: "1", objectFit: "cover", borderRadius: "8px" }}
          />
        </a>
      ))}
    </div>
  );
}
index.html
<div id="instagram-feed" style="display:grid; grid-template-columns:repeat(auto-fill,minmax(200px,1fr)); gap:1rem;"></div>

<script>
  fetch("https://api.feedfusion.dev/v1/feed/feed_abc123", {
    headers: { Authorization: "Bearer ff_live_abc123" },
  })
    .then((res) => res.json())
    .then(({ data }) => {
      const grid = document.getElementById("instagram-feed");
      data.forEach((post) => {
        const link = document.createElement("a");
        link.href = post.permalink; link.target = "_blank"; link.rel = "noopener noreferrer";
        const img = document.createElement("img");
        img.src = post.thumbnailUrl ?? post.mediaUrl;
        img.alt = post.caption?.slice(0, 120) ?? "Instagram post";
        img.style.cssText = "width:100%;aspect-ratio:1;object-fit:cover;border-radius:8px;";
        link.appendChild(img); grid.appendChild(link);
      });
    });
</script>

Use cases

Built for how developers actually work

Coming soon

For agencies and freelancers

One Agency account covers every client site you manage. Unlimited feeds, no per-client billing, no "Powered by FeedFusion" badge on anyone's site.

Coming soon

For hospitality and tourism

Hotels, restaurants, and tour operators post to Instagram every day. FeedFusion keeps that content live on their website automatically — no staff action required.

FAQ

Questions before you sign up

FeedFusion is a hosted Instagram feed widget for websites. You connect your Instagram Business or Creator account once, FeedFusion caches the feed in our database, and you drop a small snippet on your site (any builder, any framework) to render it.

You sign in, authorize Instagram via Meta's official OAuth, and FeedFusion takes care of token refresh and feed updates on a daily schedule. Drop the widget snippet on your site, or hit the JSON API directly if you prefer to build your own layout.

Yes. The Free plan covers one Instagram account, up to 10,000 widget views per month, and 10 manual feed refreshes. Pro is €5/month for five accounts and 100,000 views; Agency is €15/month with no caps.

Any site that lets you paste a snippet of HTML and JavaScript: Webflow, Wix, Squarespace, Framer, WordPress, Shopify, custom React or Next.js, plain HTML. The widget renders on the client. The JSON API is also available if your stack prefers to handle layout itself.

If you cancel, you drop back to the Free plan caps and your feed keeps rendering up to 10,000 views per month. Token expiration is handled automatically by the daily refresh job. If Instagram revokes access (usually after a password change), the widget shows the last cached feed and your dashboard flags the account for reconnection.

Start building for free.

One feed, full API access, no credit card.