-
Notifications
You must be signed in to change notification settings - Fork 2.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Gradio meta tags override issue #10701
Comments
Thanks @zgreathouse we'll consider proposing an API for this! cc @dawoodkhan82 |
@zgreathouse Here was the script I wrote that worked:
|
+1 I'm encountering the same issue and looking for workaround for this issue. Is it possible to patch my gradio locally? |
@dwipper Thank you for taking the time to write this script! Unfortunately, this will not serve as a workaround. It's important to note that updating meta tags via JavaScript won't work for social media previews or SEO. When social platforms and search engine crawlers visit your URL, they only parse the initial HTML response before any JavaScript executes. For proper social previews and search engine optimization, meta tags must be present in the head of the document from the start. This is why we need the head parameter for Without it, users are forced to serve their Gradio app within an iframe or implement similar workarounds. |
I had written that script more than a year ago.....at least the Google search console will pick up the tags, but I totally agree with you that the tags need to be set when the page loads, and not modified after it loads (with JS or an API). It seems that .Blocks() should have a param where all of the tag values can be set when the blocks/page load. |
Found a relatively simple workaround using gr.mount_gradio_app and registering middleware to update the meta tags. Snippetdef build_gradio_interface() -> gr.Blocks:
with gr.Blocks(title="App") as demo:
gr.HTML("<h1>App</h1>")
return demo
async def main() -> None:
# Initialize FastAPI server and register middleware
app = FastAPI()
app.add_middleware(ResponseModifierMiddleware)
# Build Gradio UI
demo = build_gradio_interface()
# Mount Gradio app
gr.mount_gradio_app(app=app, blocks=demo, path="/")
# Configure and run server
config = uvicorn.Config(app, host="0.0.0.0", port=7860)
server = uvicorn.Server(config)
await server.serve()
if __name__ == "__main__":
asyncio.run(main()) Script to Reproduce(This script assumes uv is installed on your machine.) mkdir sample-app
cd sample-app
# Initialize project
uv init
# Install dependencies
uv add bs4 fastapi gradio
# Write implementation code to hello.py
cat > hello.py << 'EOF'
import asyncio
from typing import Awaitable, Callable, Dict, List, Optional
from bs4 import BeautifulSoup
from bs4.element import Tag
import gradio as gr
from fastapi import FastAPI, Request
from fastapi.responses import Response
from starlette.middleware.base import BaseHTTPMiddleware
import uvicorn
META_TAGS: List[Dict[str, str]] = [
{ "name": "description", "content": "An open-source web application...etc." },
{ "property": "og:url", "content": "https://example.com" },
{ "property": "og:type", "content": "website" },
{ "property": "og:title", "content": "Sample App" },
{ "property": "og:description", "content": "An open-source web application...etc." },
{ "property": "og:image", "content": "https://example.com/sample-image.jpg" },
{ "property": "twitter:domain", "content": "example.com"},
{ "property": "twitter:url", "content": "https://example.com" },
{ "name": "twitter:card", "content": "summary_large_image" },
{ "name": "twitter:creator", "content": "@example_user"},
{ "name": "twitter:title", "content": "Sample App"},
{ "name": "twitter:description", "content": "An open-source web application...etc." },
{ "name": "twitter:image", "content": "https://example.com/sample-image.jpg" }
]
def update_meta_tags(html_content: str, meta_tags: List[Dict[str, str]]) -> str:
soup = BeautifulSoup(html_content, "html.parser")
head: Optional[Tag] = soup.head
# Remove existing meta tags that would conflict with our new ones
for meta_tag in meta_tags:
attr_type = "name" if "name" in meta_tag else "property"
attr_value: Optional[str] = meta_tag.get(attr_type)
existing_tags = head.find_all("meta", attrs={attr_type: attr_value})
for tag in existing_tags:
tag.decompose()
# Add the new meta tags to the head section
for meta_info in meta_tags:
new_meta: Tag = soup.new_tag("meta")
for attr, value in meta_info.items():
new_meta[attr] = value
head.append(new_meta)
return str(soup)
class ResponseModifierMiddleware(BaseHTTPMiddleware):
async def dispatch(
self,
request: Request,
call_next: Callable[[Request], Awaitable[Response]]
) -> Response:
response: Response = await call_next(request)
if request.url.path == "/" and response.headers.get("content-type", "").startswith("text/html"):
response_body = b"".join([chunk async for chunk in response.body_iterator])
headers = dict(response.headers)
try:
content: str = response_body.decode("utf-8")
modified_content: bytes = update_meta_tags(content, META_TAGS).encode("utf-8")
headers["content-length"] = str(len(modified_content))
return Response(
content=modified_content,
status_code=response.status_code,
headers=headers,
media_type=response.media_type
)
except Exception:
return Response(
content=response_body,
status_code=response.status_code,
headers=headers,
media_type=response.media_type
)
return response
def build_gradio_interface() -> gr.Blocks:
with gr.Blocks(title="App") as demo:
gr.HTML("<h1>App</h1>")
return demo
async def main() -> None:
# Initialize FastAPI server and register middleware
app = FastAPI()
app.add_middleware(ResponseModifierMiddleware)
# Build Gradio UI
demo = build_gradio_interface()
# Mount Gradio app
gr.mount_gradio_app(app=app, blocks=demo, path="/")
# Configure and run server
config = uvicorn.Config(app, host="0.0.0.0", port=7860)
server = uvicorn.Server(config)
await server.serve()
if __name__ == "__main__":
asyncio.run(main())
EOF
# Serve application
uv run hello.py &
# Give server time to initialize
sleep 2
if command -v open >/dev/null 2>&1; then
# macOS
open http://localhost:7860
elif command -v xdg-open >/dev/null 2>&1; then
# Linux
xdg-open http://localhost:7860
elif command -v start >/dev/null 2>&1; then
# Windows
start http://localhost:7860
else
echo "Server started! Open http://localhost:7860 in your browser"
fi |
Describe the bug
Problem Description
When attempting to set custom meta tags in a Gradio application via the head parameter for
Blocks
, Gradio overrides or conflicts with custom meta tags, particularly Open Graph and Twitter Card meta tags. This makes it difficult to properly set up social media previews for a Gradio application.Steps to Reproduce
(See attached sample code)
Expected Behavior
Custom meta tags provided through the head parameter should take precedence over any default meta tags Gradio adds, especially Open Graph and Twitter Card meta tags.
Actual Behavior
Gradio overwrites the custom meta tags with its own values.
The specific tags I notice this behavior with are:
property=og:description
property=og:image
name=twitter:creator
name=twitter:description
name=twitter:image
Impact
This issue prevents Gradio applications from properly setting up social media previews, which is critical for applications that are shared on platforms like Twitter, Facebook, Slack, and other social media sites. Without the ability to set custom meta tags, Gradio applications cannot control how they appear when shared on these platforms. (There are work arounds like serving the gradio app in an iframe, but it would be so much simpler if the
head
parameter worked as expected.)Possible Solution
Consider adding a specific parameter for social media meta tags or enhancing the existing head parameter to ensure custom meta tags take precedence over any default values.
Have you searched existing issues? 🔎
Reproduction
Screenshot
No response
Logs
System Info
Severity
I can work around it
The text was updated successfully, but these errors were encountered: