Instagram Embed
Embed Instagram posts, reels and IGTV videos anywhere inside an article. Editors paste either a post URL or Instagram's full embed code ā both are reduced to a clean permalink, so no tracking parameters or markup end up in your content. A live preview inside the editor shows what was picked before publishing. Ships a separate `/render` entry point with a React component and a @portabletext/react mapping, so the frontend renders posts without importing `sanity` into the app bundle.
Install command
npm i sanity-plugin-sgntech-instagram-embed
sanity-plugin-sgntech-instagram-embed
Embed Instagram posts, reels and IGTV videos anywhere inside a Sanity Studio article ā plus a React renderer for your frontend.
What you get
- An
instagramPostblock for Portable Text ā editors drop it between paragraphs, wherever the post belongs. - Paste either a post URL or Instagram's full
<blockquote>embed code. Both are reduced to a clean permalink, so no tracking parameters or markup end up in your content. - Posts, reels (
/reel/,/reels/) and IGTV (/tv/) links are supported, including links that carry a profile segment. - A live preview of the post inside the editor, so you can see what you picked before publishing.
sanity-plugin-sgntech-instagram-embed/renderā a React component and a@portabletext/reactmapping for the frontend. That entry point does not importsanity, so your app bundle stays clean.
Installation
npm install sanity-plugin-sgntech-instagram-embedRequires Sanity Studio v5 or v6 and React 18 or 19.
š¦ On npm: sanity-plugin-sgntech-instagram-embed
Usage in the Studio
Add the plugin and register the block in the Portable Text field it should be available in:
// sanity.config.ts
import {defineArrayMember, defineConfig, defineField} from 'sanity'
import {instagramEmbed} from 'sanity-plugin-sgntech-instagram-embed'
export default defineConfig({
// ...
plugins: [instagramEmbed()],
schema: {
types: [
{
type: 'document',
name: 'article',
fields: [
defineField({
type: 'array',
name: 'body',
of: [
defineArrayMember({type: 'block'}),
defineArrayMember({type: 'instagramPost'}), // ā the embed block
],
}),
],
},
],
},
})Editors then pick Instagram post from the "Add item" menu of the editor, paste a link or an embed code, and optionally switch the caption on.
Options
instagramEmbed({
name: 'instagramPost', // schema type name
title: 'Instagram post', // label in the editor's insert menu
captionedByDefault: false, // initial value of the "Show caption" field
showEmbedPreview: true, // render the post while the block is open in the editor
})Stored value
{
"_type": "instagramPost",
"_key": "a1b2c3",
"url": "https://www.instagram.com/p/DbdPtqcDQs3/",
"captioned": true
}Only the canonical permalink is stored. Everything else ā author, image, caption ā is fetched by Instagram at render time, which is what their embed terms require.
Rendering in your frontend
With @portabletext/react
import {PortableText} from '@portabletext/react'
import {instagramPortableTextComponents} from 'sanity-plugin-sgntech-instagram-embed/render'
export function ArticleBody({body}) {
return <PortableText value={body} components={instagramPortableTextComponents} />
}Merge it with your own components when you have more block types:
const components = {
types: {
...instagramPortableTextComponents.types,
image: MyImageBlock,
},
}Custom type name or fixed options:
import {createInstagramPortableTextComponents} from 'sanity-plugin-sgntech-instagram-embed/render'
const components = createInstagramPortableTextComponents({
typeName: 'socialEmbed',
className: 'my-embed',
maxWidth: 480,
})Standalone component
import {InstagramEmbed} from 'sanity-plugin-sgntech-instagram-embed/render'
;<InstagramEmbed url="https://www.instagram.com/p/DbdPtqcDQs3/" captioned maxWidth={540} />The component renders the same markup Instagram's own embed code produces and loads
https://www.instagram.com/embed.js once per page. It is safe to server-render: the script is only
touched inside effects, and before it loads ā or if a content blocker drops it ā the block stays a
plain link to the post.
Helpers
import {isInstagramInput, parseInstagramInput} from 'sanity-plugin-sgntech-instagram-embed/render'
parseInstagramInput('https://www.instagram.com/reels/Cx1y2z3AbC/?utm_source=ig_web_copy_link')
// => {id: 'Cx1y2z3AbC', kind: 'reel', permalink: 'https://www.instagram.com/reel/Cx1y2z3AbC/'}Notes
- Content Security Policy: the embed loads scripts and frames from Instagram. If your site sets a
CSP, allow
script-src https://www.instagram.comandframe-src https://www.instagram.com. - No Subresource Integrity:
embed.jsis an unversioned, mutable file on Instagram's servers, so anintegrityhash would break the embed on their next deploy. This is the same trade-off every official Instagram embed makes. - Private or deleted posts cannot be embedded ā Instagram renders a placeholder instead.
- This project is not affiliated with, endorsed by, or sponsored by Instagram, Meta or Sanity.
Develop
npm install
npm test # parser unit tests
npm run lint
npm run build
npm run link-watch # build + publish to a local yalc repo for Studio testingBuilt with @sanity/plugin-kit. See Testing a plugin in Sanity Studio for the local development loop.
License
MIT Ā© SGNTech
