Skip to content

RFC: social cards #2968

Open
Open

Description

@slorber

Issue for idea already expressed here: #2267 (comment)

Dynamic Social Cards

You might have noticed that some people / companies have an automated way to generate social cards that adapt to the underlying content (generating an image from query string params)

I think this would cool if by default, all Docusaurus docs/blogs would generate custom social cards, if the user did not define any custom social image.

This way, all Docusaurus links pasted to a social media would have a beautiful image.

By default we could even include a discrete Docusaurus + Slash logo for growth hacking 🤪

Vercel has a nice project to do this easily: https://github.com/vercel/og-image

We could fork this project, host our own variant (can be free on Vercel), and use it for D2 website, + allow other sites to use it as well.

Curretly, Docusaurus can have a default social card, but it's static and does not adapt to the content::

image

Here's some examples of dynamic/automated social cards:

image

image

image

image

Activity

  1. added
    proposalThis issue is a proposal, usually non-trivial change
    status: needs triageThis issue has not been triaged by maintainers
    mlhMajor League Hacking Fellowship
    status: claimedIssue has been claimed by a contributor who plans to work on it.
    and removed
    status: needs triageThis issue has not been triaged by maintainers
    on Jun 19, 2020
  2. slorber commented on Jun 19, 2020

    @slorber
    CollaboratorAuthor

    Notes, there are many ways to handle these social cards.

    • We could generate the cards as a build step, using a headless chromium instance in the CIs that support it.
    • We could host lambdas to generate the images remotely
    • We could use saas services like Cloudinary...

    Interesting blog post: https://www.swyx.io/writing/jamstack-og-images/


    @JoelMarcey

    I think this is a good idea and I would be interesting in having this implemented. As far as how to implement it, I have no strong feelings. I am generally in favor of utilizing other solutions for specific features if we believe that the cost of implementing it ourselves would be so much greater. That said, we lose a little bit of control of our destiny by doing that. I am definitely curious which way others think we should go here.

    What I think about potential implementations:

    Generating the images at build time

    Would require some kind of headless browser in the build process. I think it's likely to complicate the build process, make it slower, less portable, and potentially exceeding free quotas of popular free CIs. I think it's not the best solution.

    Seen this being done here with Gasby:
    https://andrewingram.net/posts/automatic-social-cards-with-gatsby/

    Using a SaaS

    Some people are using a SaaS like Cloudinary to generate these cards, so they don't have to host any infrastructure.

    For example:
    https://www.learnwithjason.dev/blog/auto-generate-social-image/

    Self hosted

    We could create our own solution and host it.

    Other solutions are possible, but I mean forking https://github.com/vercel/og-image as a docusaurus-images project, and hosting it on Vercel for free (or negotiate some kind of free open-source usage with them).

    We would make the service flexible enough so that it works great for most of the sites, yet enabling users to self host an alternative service if our default service does not suit their needs.


    What I think we should do:

    • Create a docusaurus-images (can be a fork of vercel/og-image)
    • Make it flexible enough for our need (querystring should enable to customize the social card image, enable/disable a Docusaurus stamp, show docs version...)
    • Host it on Vercel, making it available by default to all without having to do anything
    • Expose a configuration function that takes params of the page, and return the og image url, (which by default would use the service we host)

    This way, we don't complicate the build by default, yet we enable users to craft their own social image urls. They could self-host their own fork of vercel/og-images, use external services like Cloudinary, or even add the image generation as a build step using a docusaurus postBuild plugin.

  3. FocalChord commented on Jun 22, 2020

    @FocalChord
    Contributor

    hi! me and @Drewbi will be working on this issue :)

  4. slorber commented on Jun 22, 2020

    @slorber
    CollaboratorAuthor

    Great!

    @anshulrgoyal also suggested we could simply use an image processing lib like sharp to create the card at build time. That's simpler than using a headless chrome, and that's worth creating a POC to see how far we can go with this approach.

  5. anshulrgoyal commented on Jun 22, 2020

    @anshulrgoyal
    Contributor

    I was suggesting creating some template for cards and then allowing the user to provide custom stuff like text, icons, logo, images cards and we can have templates that can read mark down and extract stuff from it like for blog we can extract image and title, author and create image from it.

  6. slorber commented on Jun 22, 2020

    @slorber
    CollaboratorAuthor

    Yes, in the end we should be able to add a meta og image tag in generated pages + an image in the build folder. We also need to think about where we plug this image file generation step, we don't have anything like that in D2 afaik. Also need to think about how to make it generic so that it can work for docs, blog, pages... what's the url of such image etc... Not so simple :)

  7. Drewbi commented on Jun 23, 2020

    @Drewbi
    Contributor

    I'd personally prefer customizing the existing og-image project as many of the features are very relevant to what we are trying to achieve and all that would be required in terms of modification would be altering the html/css that gets generated internally by the function.

    In order to integrate the process locally at build time we would have to create and store an image for every page and either keep track of updates or regenerate the images on the next build. While possible, at this point I feel the API would lend itself quite nicely to the job and would allow for a light weight and easy implementation. It would also allow for users to swap out endpoints if they want like @slorber mentioned.

    The customization of fields would be as easy as including or leaving out fields from the query string, eg. og-docusaurus.now.sh/main%20text?logo=""&author=""&sitetitle=""&docv="2.13.4" Any of these fields could be left out and it could be handled by the API.

    Either way, if we agree on some desirable fields, I can start creating designs/mockups 🎨

  8. slorber commented on Jun 23, 2020

    @slorber
    CollaboratorAuthor

    Some random thoughts.

    I think it should be integrated at the theme classic level. Other themes would be responsible for adding themselves the og image system they want (if they do).

    I think the theme should allow a function to generate the og image url for each page. It would take some data we provide as parameter

    const config { 
      themeConfig: {
        createOGImage: ({data,defaultImage}) => {
          if (data.type === "myCustomDocType" {
            return "https://cloudinary.com/someThing?"+serialize({title: data: title});
          }
          return defaultImage; // defaultImage would be an url to the hosted og-docusaurus hosted service 
        }
      }
    }

    Eventually, we could allow the user to generate himself the images at build time using an async function?

    const config { 
      themeConfig: {
        createOGImage: async (data) => {
            const relativeFilePath = path.join("og_images",random()+".jpg");
            const filePath = path.join(__dirname,"build","og_images",random()+".jpg");
            await writeFile(filePathgenerateOgImageWithSharp(data));
            return "https://myDocusaurusSite/"+baseUrl + relativeFilePath;
        }
      }
    }

    This function couldn't be called from React directly (as the browser does not have access to nodejs apis like sharp/fs etc), so I think the blog/docs plugin should call it with the blog/doc metadata, and inject it into the theme components as props. (BlogPostPage/DocItem)


    Not totally sure about this api, feedbacks welcome. We should probably make the system generic enough so that it can be used as well for custom pages (+ the upcoming markdown pages: #2947).


    @Drewbi I think it's safe to say that we need at least 3 types of social cards:

    • docs: title, version?...
    • blog: title, author, author picture, tags...
    • pages: title

    I think the fields should vary according to the kind of docs, so we probably need multiple designs.

    In all cases I think including the site logo is nice, and an opt-out Docusaurus logo for growth hacking 🤪

  9. anshulrgoyal commented on Jun 23, 2020

    @anshulrgoyal
    Contributor

    @slorber I was thinking of adding it to some place like StaticSiteGenerator plugin. We can allow the user to modify options and pass a custom function that will be envoked inside ejs, with all the page meta data

  10. anshulrgoyal commented on Jun 23, 2020

    @anshulrgoyal
    Contributor

    Some site bots don't render javascript

  11. 40 remaining items

  12. opXmoon commented on Mar 7, 2023

    @opXmoon

    anybody have video tutorial i don't [really] understand im noob , Tell me how to create Square image preview for facebook

    Check here the sample dont know how it works - click

  13. nandorojo commented on Jun 26, 2023

    @nandorojo

    Has anyone gotten satori working with Docusaurus?

  14. anaclumos commented on Jun 26, 2023

    @anaclumos
    Contributor
  15. added a commit that references this issue on Oct 6, 2023
  16. ZenaMel commented on Oct 26, 2023

    @ZenaMel
    Contributor

    I tried adding a static social card but the option "image" is unrecognized by docusaurus v^2.0 and I can't seem to find any documentation about adding (global) social cards here: https://docusaurus.io/docs/seo

    trace:

    [ERROR] Error: These field(s) ("image",) are not recognized in docusaurus.config.js.
    If you still want these fields to be in your configuration, put them in the "customFields" field.
    See https://docusaurus.io/docs/api/docusaurus-config/#customfields    
        at validateConfig (C:\PRODUCT-DOCS\node_modules\@docusaurus\core\lib\server\configValidation.js:228:15)
        at loadSiteConfig (C:\PRODUCT-DOCS\node_modules\@docusaurus\core\lib\server\config.js:40:62)
        at async loadContext (C:\PRODUCT-DOCS\node_modules\@docusaurus\core\lib\server\index.js:31:63)
        at async load (C:\PRODUCT-DOCS\node_modules\@docusaurus\core\lib\server\index.js:74:21)
        at async Command.start (C:\PRODUCT-DOCS\node_modules\@docusaurus\core\lib\commands\start.js:44:19)
    [INFO] Docusaurus version: 2.4.1
    Node version: v18.12.1
    error Command failed with exit code 1.
    info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
    
    
  17. kamranayub commented on Oct 28, 2023

    @kamranayub

    I'll be investigating this for our work over on excaliburjs/Excalibur and we are on CF Pages; which means I think we could bake this into a Cloudflare Pages Function to handle (and they have a generous free tier + we can take advantage of CDN caching). As another alternative to Vercel. I haven't looked over it in detail, I've only skimmed over the thread.

  18. jcubic commented on Mar 11, 2024

    @jcubic

    Just my few cents, since I found this issue.

    How about using JSX like everything in Docusaurs and create SVG file out of it. Then render it into pure SVG file that is then converted to png. But only on npm run build.

    Note that I can do this on my own, but I only needs hooks into the Docusaurs system, the API that will trigger on every build that I can access blog data, similar to RSS. I could probably abuse RSS for this, but Docusaurs may complain that the image file is missing when it builds the site.

  19. slorber commented on Mar 12, 2024

    @slorber
    CollaboratorAuthor

    Note for context we are resuming work on this feature.

    How about using JSX like everything in Docusaurs and create SVG file out of it. Then render it into pure SVG file that is then converted to png. But only on npm run build.

    If you look at my answer here: #9941
    That's exactly the plan we are working on, using Satori to convert JSX + CSS/Tailwind to SVG and Resvg to generate images.

    Here's @OzakIOne POC: OzakIOne/local-og-image-generator#1

    We'll deploy that to an edge runtime letting you customize things with query string parameters, and try to see if we could partner with a host like Vercel to provide this feature as a service.

    And we'll also expose the ability to generate images through a Node API for those that do

    And we'll make the repo easy to fork, customize and deploy yourself, in case our default design and customization options are not good enough.

    Note that I can do this on my own,

    For sure, cf the PR above, generating images can be done in userland.

    I only need hooks into the Docusaurs system

    Actually... that's the complicated part here 😅

    How do we design those hooks so that we allow users to be able to generate images through a Node.js lib, or generate URLs targeting a remote image service endpoint.

    How do we make it efficient so that rebuilding your site takes less time?

    How does it work for MDX docs? And how does it work for pure JSX pages? For both Node API calls and remote service urls.

    How do we enable third-party plugin authors to leverage this without too much boilerplate and the risk of having diverging integrations? Can we figure out how to enable this on third-party plugins, without even their authors having to write code?

    These are the questions to answer. If you have those answers, let me know 😄

  20. jcubic commented on Mar 12, 2024

    @jcubic

    I've successfully generate social card in userland. By adding code to createFeedItems handler. It's a hack, but works.

    Here is an example Card:

    N/A is because of missing date of the blog post.

    The code look like this:

    createFeedItems: async ({ blogPosts,...params }) => {
        if (isProd) {
            await Promise.all(blogPosts.map(blogPost => {
                const slug = blogPost.metadata.permalink.replace(/^.*\//, '');
                const title = blogPost.metadata.title;
                const fullname = 'Jakub T. Jankiewicz';
                const avatar = 'https://github.com/jcubic.png';
                return renderSocialCard({ title, fullname, avatar, slug });
            }));
        }
        const feedItems = await params.defaultCreateFeedItems({ blogPosts, ...params });
        feedItems.forEach((feedItem,index) => {
            const blogPost = blogPosts[index]!;
            const permalink = blogPost.metadata.permalink;
            const excerpt = blogPost.content.replace(/<!--\s*truncate\s*-->[\s\S]*$/, '').trim();
            const html = (marked.parse(excerpt) as string) + `<br/><a href="${permalink}">see the rest of the article</a>`
            feedItem.content = html;
        });
        return feedItems;
    }

    is located here: https://github.com/jcubic/lips-website/tree/docusaurus/docs

    it uses render function from src/utils.ts that do all the job.

    The reason why I use puppeteer is that I Have foreign object with HTML inside (p tag) to have proper line wrapping and I think it requires real browser. It doesn't render in Inkscape.

    So what is missing:

    • access to slug (so I can generate filename)
    • access to authors
    • A way to connect with HTML
  21. slorber commented on Mar 12, 2024

    @slorber
    CollaboratorAuthor

    createFeedItems is a blog-only feature, and a feed-only feature.

    People here want to generate social cards for docs and third-party plugins too, and not just blog RSS entries. The solution we will implement can't be based on that.

  22. jcubic commented on Mar 12, 2024

    @jcubic

    Sure, but the API can be literally the same, it only needs to be triggered on every page instead of only blog posts, and you need to pick a good name.

    I also find all missing properties except slug. And still have no idea how to add this to HTML.

  23. slorber commented on Mar 12, 2024

    @slorber
    CollaboratorAuthor

    Sure, but the API can be literally the same, it only needs

    @jcubic "it only" assumes it's easy, but from what I read you don't plainly understand the problem space, and only see your use case while we try to generalize a solution.

    This feature is not related to the blog, not related to the feed. Our other plugins and third-party plugins might as well have a behavior that is far from how the blog plugin works, so don't think that a solution for a blog could be generalized that easily. Unlike blog posts, docs have versions. It is not just a "list of items" on which there is an image attribute to set.

    We already have a createFrontMatter generic API that you could use to automatically generate an extra image front matter if you want to. But that will only work for Markdown-centric documents, and not React pages. This might be good enough for your use case, but is definitively not the general solution we try to create here.

    We produce pages for which we might want to generate a custom social card, that do not even belong to a Markdown document or React page component. This is notably the case for blog tags pages, blog paginated lists, blog archive page, upcoming blog authors pages, docs autogenerated categories, and more fancy pages that we could create in the future.

  24. armchairancap commented on Nov 11, 2024

    @armchairancap

    https://github.com/Kas-tle/docusaurus-og with Vercel Satori. Haven't tried it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    featureThis is not a bug or issue with Docusausus, per se. It is a feature request for the future.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions