react-seo-meta-tags
    TypeScript icon, indicating that this package has built-in type declarations

    1.2.1 • Public • Published

    react-seo-meta-tags npm version

    SEO metatags for React apps, originally designed for a Gatsby blog site with react-helmet. But it should work with any React setup, such as Next.js apps.

    The motive behind it was the infuriating complexity of SEO coupled with the fact there wasn't any simple and understandable SEO packages out there for React.

    Example Gatsby site

    How to install

    Requires react >=16.2.0. You might also want to use react-helmet.

    npm i react-seo-meta-tags
    

    How to use

    With react-helmet:

    import React from 'react'
    import Helmet from 'react-helmet'
    import { ReactSEOMetaTags } from 'react-seo-meta-tags'
    // Or
    import ReactSEOMetaTags from 'react-seo-meta-tags'
    
    ...
        <ReactSEOMetaTags
          render={(el: React.ReactNode) => <Helmet>{el}</Helmet>}
          website={{ ...siteMetadata }}
        />

    Next.js:

    import Head from 'next/head'
    import { ReactSEOMetaTags } from 'react-seo-meta-tags'
    
    ...
        <ReactSEOMetaTags
          render={(el: React.ReactNode) => <Head>{el}</Head>}
          website={{ ...siteMetadata }}
        />

    where siteMetadata could be:

    {
      url: 'https://google.com/about',
      title:  'This is a 70 character long title with a lot of padding to make it so!',
      datePublished: '2019-10-06T13:56:03.123Z',
      description: 'This is a 200 character long description of this web page which is quite interesting and which describes its contents well with a lot of relevant keywords and isn\'t just general marketing mumbo-jumbo.',
      language: 'en-US',
      image: 'http://website.com/image.png',
      author: {
        email: 'person@gmail.com',
        name: 'John Smith',
        image: 'http://john.me/my-face.jpg',
      },
      site: {
        siteName: 'IMDb',
        searchUrl: 'https://www.google.com/search?q=',
      }
    }

    It appears both react-helmet and Next.js are a bit picky how they accept meta tags. ReactHelmet being the more choosy as it doesn't accept any nesting. Next.js works for some children but not all and therefore using the render function is required.

    Without:

    import React from 'react'
    import { ReactSEOMetaTags } from 'react-seo-meta-tags'
    
    ...
        <ReactSEOMetaTags
          website={{ ...siteMetadata }}
          breadcrumb={[
            { name: 'My Site', url: 'https://me.com' },
            { name: 'Blog', url: 'https://me.com/blog' },
          ]}
          organization={{
            name: 'Google',
            legalName: 'Google Inc',
            url: 'https://google.com',
            logo: 'https://google.com/logo.jpg'
          }}
          blogPost={{ ...blogPost }}
          facebook={{ facebookAppId: 'abc123' }}
          twitter={{ twitterUser: '@mickey_mouse' }}
        />

    In the previous example the inheritance of the properties goes like this: website < blogPost < facebook | twitter. So if the same property (eg image) is specified in blogPost and facebook, the facebook object's property will be the one used in its respective tag (og:image in this case).

    The current properties shown are the ones I've seen websites use the most. Most sites don't even use JSON-LD, for example Google doesn't use it even though they have been a big contributor to it. So yeah, I wouldn't recommend going too deep into this rabbit hole. The API is complicated and if you feel there's something missing create a PR.

    General page

    For example a front or about page. I recommend adding just the website property with an organization if you have one. In that case remember to add good enough list of sameAs URLs (they seem to be helpful). Breadcrumb if you feel it makes sense. NOTE: Always remember to add the title of the page, it's used also to render a <title> tag so be aware!

    For the image of a general page I just used the logo for my example site. I strongly recommend having that image in 2:1 ratio eg 440x220 in order to make it appear nicely when sharing.

    Blog post

    For a blog post, provide all the blogPost values. I know it's a bit of work, but this way you'll avoid any complaints from SEO validation tools such as https://search.google.com/structured-data/testing-tool. For Facebook and Twitter you can customize the image sizes or titles as they appear when the post is shared. I only added the tags I thought were useful, if something's missing please create an issue or PR. Also Google expects BlogPosts's to have publisher property and that to be an organization. In Schema.org spec Person is also a valid value, but Google doesn't think so. You could just use yourself as a fake organization I guess if nothing else.

    API

    ReactSEOMetaTags currently is used for only two types of pages: website and blogpost.

    Website is a general page with some added Facebook (og) and Twitter tags for better SEO. Also includes JSON-LD schema.

    BlogPost is a page for a blogpost (og:type article) that can have quite a few properties. I made only title to be required but you probably want at least description, image, datePublished and author to be specified. Well in general it's probably best for SEO purposes to include most of them, if not all. Each bit helps, but real traffic will always boost your SEO much more than these types of meta tags.

    For more custom tags you either have to render them by yourself or, and I hope you will, create a PR that includes the missing features in a compact and well documented way. There's so much boilerplate already with these tags so I don't want to include some random tags without knowing what they are for.

    export interface ReactSEOMetaTagsProps {
      render?: (el: React.ReactNode) => React.ReactNode
      website?: WebsiteProps
      breadcrumb?: BreadcrumbList
      organization?: OrganizationProps
      blogPost?: BlogPostProps
      facebook?: FacebookProps
      twitter?: TwitterProps
    }
    
    /**
     * https://schema.org/WebSite
     */
    export interface WebsiteProps {
      url?: string // The URL of this page (eg https://google.com/about)
      title: string // Maximum 70 characters.
      // The original publication date. ISO 8601 timestamp eg "2019-10-06T13:56:03.123Z"
      // Don't know how useful for random webpages. Add it at least for blog posts.
      datePublished?: string
      description?: string // Maximum 200 characters.
      language?: string // Default "en-US" https://en.wikipedia.org/wiki/IETF_language_tag and https://datahub.io/core/language-codes
      image?: string // URL to the image, PNG, JPEG, or GIF recommended.
      imageAlt?: string // Alt for the image
      // Possibly redundant property. But at least bots can scrape your email and that's fun right? :)
      author?: PersonProps
      site?: {
        // "If your object is part of a larger web site, the name which should be displayed for the overall site. e.g., "IMDb"."
        // At least Telegram uses this as gray text above the title when sharing links.
        siteName?: string
        // If your website has a search functionality, enter the URL with parameter here eg "https://www.google.com/search?q="
        searchUrl?: string
      }
    }
    
    /**
     * https://developers.facebook.com/docs/sharing/webmasters/
     * http://ogp.me/
     */
    export interface FacebookProps {
      title?: string // The title of your article without any branding such as your site name.
      description?: string // A brief description of the content, usually between 2 and 4 sentences.
      language?: string // Used for og:locale. Default "en-US"
      // Facebook recommends 1200x630 size, ratio of 1.91:1. PNG, JPEG, or GIF.
      // But if you want your image to be displayed as a smaller image (aka thumbnail, similar to 'summary' Twitter card),
      // your image should be smaller than 400x209 and preferably with a ratio of 1:1. Unless your image can be cropped
      // into a 1:1 box without making it look bad. So you probably want to use something like 200x200.
      // Note the "minimum size constraint of 200px by 200px".
      image?: string
      imageAlt?: string // Alt for the image
      video?: string // "A URL to a video file that complements this object."
      audio?: string // "A URL to an audio file to accompany this object."
      facebookAppId?: string // "Insights lets you view analytics for traffic to your site from Facebook."
    }
    
    /**
     * https://developer.twitter.com/en/docs/tweets/optimize-with-cards/overview/markup.html
     */
    export interface TwitterProps {
      title?: string // Title of content (max 70 characters). Fallback: og:title.
      description?: string // Description of content (maximum 200 characters). Fallback: og:description.
      image?: string // Twitter card image, optimal ratio 1.91:1. Recommended: 1200x628. PNG, JPEG, or GIF. Fallback: og:image.
      imageAlt?: string // Alt for the image. Fallback: og:image:alt.
      // So since I saw that the large image looked dumb if you are using your faceshot as the image, I added the smaller 'summary'
      // type as an option. It should be in 1:1 scale. Also there exists 'player' and 'app' types but since I'm not using those,
      // I'm not going to spend my precious time figuring out how they work for now.
      cardType?: 'summary_large_image' | 'summary' // Default 'summary_large_image'
      twitterUser?: string // @username of content creator.
      twitterSite?: string // @username of the site eg @nytimes
    }
    
    /**
     * https://schema.org/BlogPosting
     */
    export interface BlogPostProps {
      // The canonical URL for your page. This should be the undecorated URL, without session
      // variables, user identifying parameters, or counters.
      url?: string
      title: string // Title of the post. Max 70 characters.
      description?: string // Should be a short description about the topic, <=200 words. Mainly for SEO purposes.
      image: string // You should add this. Just use the same image as og/twitter eg 1200x630 with 1.91:1 ratio in PNG, JPEG, or GIF.
      imageAlt?: string // Some SEO tools really want this so it's probably wise to add it
      datePublished?: string // The original publication date. Don't change arbitrarily, Google might downrank you.
      dateModified?: string // Google prefers recent content in search results and also users are more likely to click a recent article
      tags?: string[]
      /**
       * Technically either Person or Organization, but since it doesn't make any sense to not to credit this content to a human, use person.
       * From schema.org:
       * "Please note that author is special in that HTML 5 provides a special mechanism for indicating authorship
       * via the rel tag. That is equivalent to this and may be used interchangeably."
       * Which means.. something.
       */
      author?: PersonProps
      /**
       * You should add this since otherwise Google's structured-data tool will complain...
       * However https://webmasters.stackexchange.com/questions/110332/personal-blog-using-structured-data-fails-validation-on-publisher
       */
      publisher?: OrganizationProps
      site?: {
        // "If your object is part of a larger web site, the name which should be displayed for the overall site. e.g., "IMDb"."
        // Used for og:site_name
        siteName?: string
      }
    }
    
    /**
     * https://schema.org/BreadcrumbList
     */
    export type BreadcrumbList = BreadcrumbProps[]
    
    export interface BreadcrumbProps {
      url: string
      title: string
      image?: string
    }
    
    /**
     * https://schema.org/Person
     */
    export interface PersonProps {
      email?: string
      name?: string
      image?: string
    }
    
    /**
     * https://schema.org/Organization
     */
    export interface OrganizationProps {
      '@type'?: string // Default 'Organization'. You could use eg 'Corporation'.
      description?: string
      name: string // Eg "Google"
      legalName?: string // Eg "Google Inc"
      logo: string // URL to the logo image.
      // List of other webpages referencing this organization, eg Wikipedia, Facebook, Twitter, Instagram etc.
      // Will show these sites alongside your website in Google search results and probably boost your SEO rank too.
      sameAs?: string[]
      url: string // URL to the organization, eg "https://abc.xyz"
      parentOrganization?: OrganizationProps // You can nest as many organizations as you'd like, dunno how useful it's
    }

    How to develop locally

    Requires: Node.js >= 8.

    1. Clone this repo & run npm i
    2. Star the TypeScript compiler: npm run ts:watch
    3. In another terminal go to the example project and install dependencies: cd example & npm i
    4. Start the Gatsby app with: npm start
    5. The app should open in http://localhost:8000. The changes to the source code should be reloaded automatically and be seen in the <head>'s metatags. Happy hacking!

    How to publish changes

    This one is more for the maintainers such as me. All the changes should go through PRs. But because there's no automatic CI such as Travis set up (yet), the new versions are published locally.

    1. Login to your npm account: npm login.
    2. After making changes to the code (cough pulling from master I mean), run npm run compile.
    3. Depending on the changes you have made, use either npm version patch|minor|major to update the version in package.json. Do it semantically*.
    4. It should automatically tag it, but if it didn't tag it yourself: git tag v1.5.1.
    5. Push the changes to GitHub: git push origin master && git push origin master --tags.
    6. Publish to npm: npm publish. This will push the files specified in package.json "files"-block + default files (package.json, README, LICENSE).

    *Semantically: big breaking changes is a major release, general changes or bug fixes are minor releases and patches are just some general maintenance or refactoring.

    How to contribute

    Create issues or PRs for bug reports/feedback/feature requests.

    SEO Tools

    Other resources about SEO in general

    Open Graph

    Metadata format developed by Facebook.

    http://ogp.me/

    Install

    npm i react-seo-meta-tags

    DownloadsWeekly Downloads

    247

    Version

    1.2.1

    License

    MIT

    Unpacked Size

    46.7 kB

    Total Files

    12

    Last publish

    Collaborators

    • tekk