What I’m trying to do: I have a website that hosts different articles. When someone links to my site on something like LinkedIn/Facebook, I want it to show the title/content/image from that particular page not the site general info. Note: I use hashrouting.
What I’ve tried and what’s not working:
I’m actually not sure where to begin here. I naively tried to use this, but it did nothing:
from anvil.js.window import document
document.title = “TEXT”
I haven’t used hashrouting, but just from a data-available standpoint, your Anvil App is not going to automatically know much about where it was linked from – unless that’s passed, somehow, as part of the URL that invokes your App.
So, first, make sure that the necessary information is indeed being passed. If you could show a sample URL, for the hashrouting experts to see, they may be able to take it from there.
Most of those sites use meta tags in the head section of the page. You might be able to simulate that with custom HTML forms, but it depends on whether they execute Javascript or not and other factors.
The first step is to pick a site you want to show a preview on, and then identify exactly which tags are required, and do a test by changing the standard-page.html contents in an app to see if the preview shows up the way you want.
If all that works, then you can look at if it’s possible to change it per form, which as Phil says will require hash routing, and also a lot of luck.
Those platforms also change their requirements fairly frequently, so those previews are generally a moving target. I worked on a media platform that provided Facebook previews when someone linked to a video on Facebook, and it was a pain to keep up with the changes.
Forgive me for not clarifying my solution (I was in a bit of hurry back then). But the solution requires creating HTTP endpoints in your Server Module.
Hello! I just want to say this has been working quite well. For some reason I can’t get the image portion to work, and I was wondering if you had any insights. I’ve tried using it from a public link and from the media url from the db on anvil.
Oh, I see the problem. Right now, you are only setting the image as the favicon for the url. There is an additional tag you can add for displaying a proper sized image.
@anvil.server.http_endpoint('/research/:id')
def get_research(id):
row=app_tables.research.get(id=id) #Finding the row for that research using the provided ID
title=row['Title']
description=row['Description']
image=row['Image'].url
hash_url = f"https://something.anvil.app/#research?id={id}"
html=f"""
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>{title}</title>
<meta name="description" content="{description}">
<meta property="og:image" content="{image}" />
<link rel="icon" type="image/png" href="{image}">
<script>
window.location.href="{hash_url}"
</script>
"""
return anvil.BlobMedia('text/html',bytes(html.encode()))
Thanks for the guidance on this. I created this helper class based on the details in this post. I hope it helps someone.
P.S. I have not tested the Twitter and Pinterest components, as I do not have accounts on those sites. Please let me know if they work.
Code Here:
import anvil.server
class LinkPreview:
def get_link_preview(
self,
title: str,
description: str,
hash_url: str,
image_url: str = "",
image_alt: str = "",
twitter_site: str = "",
twitter_handle: str = "",
no_pin: bool = True,
rich_pins: bool = True,
):
"""
Gets a link preview with the given parameters.
Args:
title (str): The title of the link preview.
description (str): The description of the link preview.
hash_url (str): The URL of the link preview.
image_url (str, optional): The URL of the image for the link preview. Defaults to "".
image_alt (str, optional): The alt text for the image. Defaults to "".
twitter_site (str, optional): The Twitter site for the link preview. Defaults to "".
twitter_handle (str, optional): The Twitter handle for the link preview. Defaults to "".
no_pin (bool, optional): If True, the link preview will not be pinned. Defaults to True.
rich_pins (bool, optional): If True, the link preview will be a rich pin. Defaults to True.
"""
pinterest_content = "nopin" if no_pin else ""
rich_pins = "true" if rich_pins else "false"
html = f'''<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>{title}</title>
<meta name="description" content="{description}">
<link rel="icon" type="image/png" href="{image_url}">
<meta property="og:title" content="{title}">
<meta property="og:description" content="{description}">
<meta property="og:image" content="{image_url}">
<meta property="og:image:alt" content="{image_alt}">
<meta property="og:site_name" content="{anvil.server.get_app_origin()}">
<!-- Twitter specific tags -->
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:site" content="{twitter_site}">
<meta name="twitter:creator" content="{twitter_handle}">
<meta name="twitter:title" content="{title}">
<meta name="twitter:description" content="{description}">
<meta name="twitter:image" content="{image_url}">
<meta name="twitter:image:alt" content="{image_alt}">
<!-- Pinterest specific tags -->
<meta name="pinterest" content="{pinterest_content}">
<meta name="pinterest-rich-pin" content="{rich_pins}">
<script>
window.location.href="{hash_url}"
</script>
</head>
<body>
</body>
</html>'''
return anvil.BlobMedia("text/html", bytes(html.encode()))
@classmethod
def construct_link_preview(
cls,
title: str,
description: str,
hash_url: str,
image_url: str = "",
image_alt: str = "",
twitter_site: str = "",
twitter_handle: str = "",
no_pin: bool = True,
rich_pins: bool = True,
):
return cls().get_link_preview(
title=title,
description=description,
image_url=image_url,
hash_url=hash_url,
image_alt=image_alt,
twitter_site=twitter_site,
twitter_handle=twitter_handle,
no_pin=no_pin,
rich_pins=rich_pins,
)