Skip to content
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

Custom OG images #2695

Merged
merged 19 commits into from
Jan 7, 2022
Merged

Custom OG images #2695

merged 19 commits into from
Jan 7, 2022

Conversation

smallbrownbike
Copy link
Collaborator

@smallbrownbike smallbrownbike commented Jan 6, 2022

Changes

Dynamically creates custom Open Graph images based on page content for docs, handbook, customer, and blog post pages.

Before

After

Screen Shot 2022-01-06 at 12 21 35 PM

This is cool, but how does it work?

Once the Gatsby build process is complete, we pass an HTML string containing some page data to Puppeteer for each page; it screenshots each page and saves it. That new image URL is used instead of the standard banner.png.

A semi-detailed overview of what's happening

Gatsby has a really cool API that allows you to hook into the last point of the build process: onPostBuild. This is where all of the magic takes place.

We first query for each page that we want to add a custom Open Graph image to. Right now, that's docs, handbook, customer, and blog posts.

From there, we do some initial setup:

  • Create folders for images and fonts
  • Download our font
  • Spin up a new Chromium page with Puppeteer

After setup is complete, we finally iterate through each queried page, set the content of the Chromium page with an HTML string, screenshot the page, and save it. Here's what that looks like for blog posts:

for (const post of data.blog.nodes) {
    const { title, authorData, featuredImage } = post.frontmatter
    const image = fs.readFileSync(featuredImage.absolutePath, {
        encoding: 'base64',
    })
    await createOG({
        html: blogTemplate({ title, authorData: authorData && authorData[0], image, font }),
        slug: post.fields.slug,
    })
}

What's happening in this for...of loop, though?

const image = fs.readFileSync(featuredImage.absolutePath, {
    encoding: 'base64',
})

Since the site isn't technically "live" yet, we don't have access to a public URL to insert into our HTML template. The workaround is embedding it in an <img /> element as Base64. You'll see this workaround in a few other places in the code.

await createOG({
    html: blogTemplate({ title, authorData: authorData && authorData[0], image, font }),
    slug: post.fields.slug,
})

We have an asynchronous function called createOG. This handles setting the Chromium page content, screenshotting, and saving the image. It takes an HTML string to set the Chromium page content and a slug to create the file name of the screenshot.

Each page type (handbook, docs, blog, etc.) has a custom HTML template based on these designs (S/O @corywatilo). These templates are located in /src/templates/OG. They each take different data based on the design and return an HTML string. Take a look at blog.js to see what's happening in the above example.

That's it!

@corywatilo
Copy link
Collaborator

Amazing work! Is this mergeable or do we have anything else to do here? (We can split off the other unfinished open graph images into another PR since some still need to be designed - mostly the static ones.)

@smallbrownbike
Copy link
Collaborator Author

@corywatilo Currently mergeable. We can get the rest added later!

@corywatilo
Copy link
Collaborator

corywatilo commented Jan 7, 2022

Going to merge, but I did a quick run-through and found a few minor things which I'll add to a future issue for when we implement the rest of the custom images!

Handbook/Docs

Blog

Next steps

These seem to be broken

@corywatilo corywatilo enabled auto-merge (squash) January 7, 2022 20:25
Copy link
Collaborator

@corywatilo corywatilo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚀

@corywatilo corywatilo merged commit feabda2 into master Jan 7, 2022
@corywatilo corywatilo deleted the custom-og-images branch January 7, 2022 20:42
@yeldarby
Copy link

Outsider chiming in with 2 things:

  1. I shared some PostHog docs with my team in Slack & saw the dynamic open graph image and it was a really nice touch; definitely shows how much you all love your craft.
  2. It's so cool that you have a culture of building out in the open like this. Really neat that I could see it, think "Oooh, shiny. I wonder how they did that", and then find the PR on GitHub that implemented it. 👏

@jamesefhawkins
Copy link
Contributor

That's lovely feedback @yeldarby - if you'd like to read about how we got here, there's a post coming out soon (sneak preview) - we're thinking about productizing this feature too as it's own little open source project, so stay tuned

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants