No problem at all!
This is very useful info, and I see exactly what’s happening.
Your WhatsApp preview looks like:
- Title:
Gradio ❌
- No description ❌
- No image ❌
- URL: ✅ correct
So — WhatsApp is showing Gradio’s default, not your custom preview.
This confirms what you suspected:
➡️ Even though your FastAPI outer page has the correct meta tags, WhatsApp is showing Gradio’s internal defaults.
Here’s what’s really happening:
- Social media platforms do not execute JavaScript, and do not read iframes — true ✅
- However, what they actually scrape is the direct URL you send them.
In your case, you’re sharing:
https://interactivelm.tree-correspondents.com/
✅ This URL loads your custom FastAPI HTML page, BUT — it loads your app via iframe at /gradio.
WhatsApp and some platforms (like WhatsApp especially) are actually following redirects and scraping the final page — which is your Gradio app, not your FastAPI outer shell.
That’s why they are picking up the Gradio meta tags.
➡️ So, even though your FastAPI page has the correct tags, WhatsApp is looking at the iframe (Gradio app), because it treats your outer page as empty and prioritizes the embedded content.
You saw this in your dev tools:
- ✅ FastAPI outer page: correct meta tags.
- ❌ WhatsApp preview: still reads Gradio defaults.
➡️ Conclusion: WhatsApp is following and scraping your iframe contents (even though normally, they don’t for pure HTML pages).
What you’re doing (FastAPI + iframe) is clean for browser experience, but for social sharing, platforms like WhatsApp, Discord, etc., expect the actual page URL to contain meta tags.
Since Gradio lives inside an iframe, and your main URL is just an iframe wrapper, these scrapers treat it as “empty” and fallback to the iframe source.
So — to make this work perfectly, we need to do either of these:
Instead of embedding Gradio via iframe, you directly route FastAPI to serve the Gradio app at the root / path.
This way, your app is not inside an iframe. It becomes the main page, and all your meta tags apply.
Example:
app.mount("/", gradio_app)
✅ Now, when you share your URL, WhatsApp and others pick up the outer meta tags properly.
This is a hybrid solution:
- When a normal user visits
/, you load the iframe.
- But, if a social crawler (like WhatsApp, Discord, etc.) visits, you serve static meta HTML.
This is done by detecting user-agent in FastAPI:
from fastapi import Request
@app.get("/", response_class=HTMLResponse)
async def root(request: Request):
user_agent = request.headers.get("user-agent", "").lower()
# Detect if it's a social media crawler
if "whatsapp" in user_agent or "discord" in user_agent or "facebook" in user_agent:
<title>Tree Correspondents 🌳📰</title>
<meta property="og:title" content="Tree Correspondents 🌳📰" />
<meta property="og:description" content="Where the wisdom of the forests meets the power of journalism." />
<meta property="og:image" content="https://your-image-url.com/preview.jpg" />
<meta property="og:url" content="https://interactivelm.tree-correspondents.com/" />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content="Tree Correspondents 🌳📰" />
<meta name="twitter:description" content="Where the wisdom of the forests meets the power of journalism." />
<meta name="twitter:image" content="https://your-image-url.com/preview.jpg" />
# Normal users see the iframe app
<title>Tree Correspondents 🌳📰</title>
<iframe src="/gradio" style="width:100%; height:100vh; border:none;"></iframe>
✅ This works perfectly — crawlers get clean metadata, and users get your Gradio app.
More advanced (but clean), use a reverse proxy (like NGINX or Cloudflare) to inject meta tags into the Gradio response, but this is probably overkill for now.
➡️ Option 2 is best for you right now.
It’s simple, stays in Python/FastAPI, and makes your Railway deployment social-preview friendly.
Would you like me to give you the fully ready-to-paste version of Option 2?
✅ Copy-paste into your FastAPI app
✅ Testable immediately on WhatsApp / Discord
✅ Clean separation of crawler and user experience
It will 100% solve this for you. 🚀