Guide

Discord link preview buttons: format and limits

Discord link preview buttons are style-5 link buttons inside a component embed: server-rendered JSON (script#discord:component-embed or a same-site link rel=discord:component-embed) that Discordbot reads from your URL. They are not interactions, they do not use custom_id, and they must point at https. Open Graph remains the fallback.

What Discord actually fetches

Discord does not run your client bundle. If the JSON is not in the first HTML response, the card will not appear. Inline the payload in a script tag with id discord:component-embed and type application/json. The root object is { "component": { "type": 17, "components": [...] } }.

Allowed types in v1 practice: 1 (action row), 2 with style 5 (link button), 9 (section), 10 (text), 11 (thumbnail), 12 (media gallery), 14 (separator), 17 (container). Max 40 components. custom_id is rejected. Buttons must be https.

Button rules that fail in production

http URLs are dropped. custom_id is invalid on this surface. Gift and nitro copy is how scam pages get the whole domain denylisted — Tinycord blocks that language before a slug exists.

One to five buttons is enough. This editor is not a 40-component tree. If you need that, you are building a bot dashboard, not a link preview.

Why bots are the wrong tool

A bot can post a message with buttons, but then you operate a bot, privileged intents, and a command surface. Component embeds ride on the link you already wanted to paste.

Tinycord never creates a Discord application. Import a page, add Hire me or Buy or Docs, publish, paste.

Open Graph is the fallback, so ship both

OG answers “what is this link?” A component embed answers “what can I do?” — Hire me, Buy, Book a call, Docs, RSVP. Tinycord writes both on GET /p/{slug}.

If the JSON is invalid, over 40 nodes, or blocked by a WAF, readers still see a respectable OG card instead of nothing. Keep complete Open Graph tags on every page, then add a component embed wherever a button helps.

Hosted URL versus copy script

Tinycord publishes GET /p/{slug} with OG tags, Twitter tags, theme-color, and the inline script. Paste that URL in Discord. Edit the slug later; Discord recrawls in about 30 minutes.

If you already SSR your own domain, copy the script tag into that HTML. The snippet is a snapshot. Linked JSON must be same-site and under 3,000 bytes. JSON hosted on tinycord.com cannot be linked from example.com.

How to verify

View-source the page and confirm the script is in the SSR HTML. Then use Discord's Embed Debugger, or run the free Discord-ready checker. Allow Discordbot through Cloudflare; Discord's own docs warn that a JS challenge here silently kills the unfurl.

Common questions

Can a link preview button open a modal or run a command?
No. Only navigation to an https URL. Anything interactive requires custom_id and a real Discord application listening for the interaction.
Why does my payload render as a plain tile?
Almost always one of three things: the JSON is not in the server-rendered HTML, a component type is outside the allowed set, or a button uses http. Discord falls back to Open Graph rather than reporting an error.
Does Discord still use Open Graph tags?
Yes. Open Graph title, description, image, and theme-color are the fallback whenever Discord does not render a component embed for a link.
Can an Open Graph preview have buttons?
No. Open Graph only describes the page. Clickable link buttons need a Discord component embed on the same URL.

Try it on your own page

Import a URL, add buttons, and paste the hosted link in Discord.

Create a card