I don't really understand the Twitter and the Instagram. -Mia Goth
I don't really understand the Twitter and the Instagram. -Mia Goth

Image: me

Include your Instagram feed in a Gatsby site

Tags: instagram, web dev, gatsby

April 23, 2023

Gatsby & instagram

Do you want your Gatsby site to display your Instagram posts with images, captions, likes, comments and hashtags?

    Udpate:

    After a few months of experimenting, I've concluded this plugin or perhaps Instagram's underlying APIs are very unreliable. Most builds these days no longer succeed for me and looking at the repo, maintainers aren't very active.


    I've decided to remove this from my site and I'm looking for alternatives.

Check out my example here: Instagram Gatsby Page (now removed from site)

In this blog post, I will show you how to create this example. We will leverage the existing gatsby-source-instagram plugin.

Limitations and FYI

This plugin allows you to source data from Instagram using either built-in scraping for user posts, hashtag pages and user profile scraping or Graph API.

  • The plugin will re-fetch for nodes every time the develop server is restarted, which means lots of requests repeat unnecessarily. This may cause performance issues or rate limits by Instagram. Source
  • The public scraping method can only get the last 12 photos from an Instagram account or a hashtag page. It does not require an access token, but it may be blocked by Instagram if it detects too many requests from the same IP address.
  • The Graph API method requires an access token and an instagram id. It can get more data than public scraping, such as likes, comments, hashtags, media type, etc. It also has a paginate parameter to control the limit of the API call and a maxPosts parameter to limit the maximum number of posts to store.
  • The plugin will use public scraping as a fallback if the Graph API throws any exception and the username is provided.
  • If many sites that are served from the same domain are using the Instagram APIs, it may trigger Instagram to enforce rate limits for the domain. This may affect the availability of the plugin for those sites.

So, this is not a super reliable plugin but we shall let's see how it performs.

Install and configure the plugin

To install the plugin, run the following command in your terminal:

  npm install --save gatsby-source-instagram

To configure the plugin, you need to provide your username, access token and instagram id as options in your gatsby-config.js file. You can also enable hashtags and pagination if you want. Here is an example of how to use the Graph API method:


  // In your gatsby-config.js
  plugins: [
    {
      resolve: `gatsby-source-instagram`,
      options: {
        username: `username`,
        access_token: "a valid access token",
        instagram_id: "your instagram_business_account id",
        paginate: 100,
        maxPosts: 1000,
        hashtags: true,
      },
    },
  ]

Getting your config details

I followed the current processes documented in the plugin's github. For reference, I followed these steps:

For public content scraping

If you intend to use the public scraping method then you need to pass the concerning username id. You can determine it by taking the following steps:

  1. Open a browser and go to the Instagram page of the user - e.g. https://www.instagram.com/user/
  2. Right-click on the web page to open the right-click context menu and select Page Source / View page source / Show Page Source. Safari users, please make sure that the developer tools are enabled - see Enabling Web Inspector - Apple Developer
  3. Search for profilePage_. The number that follows is the username id. If you view the page source of https://www.instagram.com/user/, you will find profilePage_8556131572. So, 8556131572 is the username id of the username user.

For Graph API

If you intend to use Graph API for more reliability (note the plugin will fallback to public scrape if unsuccessful using Graph API and the username is set), there is some pain involved:

  1. Created a Facebook page (I know... :/)
  2. Create an app (register as a Meta dev to do this)
  3. Go to the Graph API Explorer
    1. Select your Facebook app
    2. Add the following permissions:
      • pages_manage_ads,
      • pages_manage_metadata,
      • pages_read_engagement,
      • pages_read_user_content,
      • pages_show_list,
      • instagram_basic
    3. Generate the token so you are prompted to associate the Page target.
    4. Select the Facebook page you created and allow access.
    5. Use the Graph API Explorer to make a GET request to me/accounts
    6. Copy the access_token in the response (we call this temporary_token)
    7. Click on the id next to name to change the explorer URL
    8. Then append ?fields=instagram_business_account&access_token={access-token} and do another GET request
    9. Save your instagram_business_account.id, this is your instagram_id
  4. Lastly, go to the Access Token Debugger:
    1. Paste your temporary_token and press "Debug"
    2. You should see this token now expires in 3 months
    3. Press "Extend Access Token" and press the new debug that appears next to the token
    4. You should see this token now never expires but sometimes 3 months is the maximum and the cause is not clear
    5. Copy this new token (we will call this access_token)

Now you will need to find a safe place to store your keys. If you're using GitHub or similar, you should use the secure variables settings for the project.

Do not accidentally push these keys to a public repo. If that happens, immediately revoke the keys by following this guide.

Graph API unsuccessful

I found that despite following the instructions, I was never able to successfully use the Graph API. I may revisit it in the future if I have a good reason but working in the Facebook dev area was a very disconnected and confusing experience.

Query the Instagram data

Query the Instagram data using GraphQL. You can use the allInstaNode query to get all the posts from your Instagram account. You can access fields such as id, caption, likes, comments, localFile (for image processing) and hashtags. Here is an example of how to query the data:


  query {
    allInstaNode {
      edges {
        node {
          id
          caption
          likes
          comments
          localFile {
            childImageSharp {
              gatsbyImageData(
                layout: CONSTRAINED, 
                placeholder: BLURRED
              )
            }
          }
          hashtags
        }
      }
    }
  }

Add the component to your site

There are 2 approaches you can take:

  • create the page using gatsby-node.js
  • create a react component

Create via gatsby-node.js

You could use the createPage API in gatsby-node.js to programmatically create a page for your Instagram feed. You can also pass the Instagram data as context to the component. Here is an example of how to do that:


  // In gatsby-node.js
  exports.createPages = async ({ graphql, actions }) => {
    const { createPage } = actions

    const result = await graphql(`
      query {
        allInstaNode {
          edges {
            node {
              id
              caption
              likes
              comments
              localFile {
                childImageSharp {
                  gatsbyImageData(layout: CONSTRAINED, placeholder: BLURRED)
                }
              }
              hashtags
            }
          }
        }
      }
    `)

    createPage({
      path: "/instagram-feed",
      component: require.resolve("./src/pages/instagram.js"),
      context: { instagramData: result.data.allInstaNode },
    })

Then you'll want a component that receives the data via context.

Here's a simple page component:


  import React from "react";
  import { GatsbyImage } from "gatsby-plugin-image";

  const InstagramPage = ({ pageContext }) => {
    const { instagramData } = pageContext

    return (
      <div>
        {instagramData.edges.map(({ node }) => (
          <div key={node.id}>
            <GatsbyImage
              image={node.localFile.childImageSharp.gatsbyImageData}
              alt={node.caption}
            />
            <p>{node.caption}</p>
            <p>{node.likes}</p>
            <p>{node.comments}</p>
            <p>{node.hashtags}</p>
          </div>
        ))}
      </div>
    );
  }

  export default InstagramPage;
  

You can copy and paste this code into your ./src/pages/instagram.js file.

Create an Instagram component

Alternatively, you can add a react component and include the GraphQL directly in the same file. Here's an example of that:


    // In components or pages folder, create your instagram component
    import React from "react";
    import { useStaticQuery, graphql } from "gatsby";
    import { GatsbyImage } from "gatsby-plugin-image";

    const Instagram = () => {
      const data = useStaticQuery(graphql`
      query {
        allInstaNode {
          edges {
            node {
              id
              caption
              timestamp
              localFile {
                childImageSharp {
                  gatsbyImageData
                }
              }
            }
          }
        }
      }`);

      const styles = {
        container: {
          display: "flex",
          flexWrap: "wrap",
          justifyContent: "center",
          alignItems: "center",
        },
        node: {
          height: 300,
          width: 300,
          overflow: "hidden",
          display: "flex",
          flexDirection: "column",
          justifyContent: "end",
          alignItems: "center",
          margin: 2,
        },
        title: {
          textAlign: "center",
          margin: 16,
        },
        overlay: {
          background: "transparent"
        }
      };

      return (
        <div style={styles.title}>
          <h1>Instagram Posts</h1>
          <div style={styles.container}>
            {data.allInstaNode.edges.map(({ node }) => (
              <>
                <a href={`https://www.instagram.com/p/${node.id}/`}>
                  <div key={node.id} style={styles.node}>

                    <GatsbyImage
                      image={node.localFile.childImageSharp.gatsbyImageData}
                      alt={node.timestamp}
                    />
                    <div style={styles.overlay}>
                      {node.caption}
                      {new Date(node.timestamp * 1000).toLocaleString()}
                    </div>

                  </div>
                </a>
              </>
            ))}
          </div>
        </div>
      );
    };

    export default Instagram;

Run the dev build

Run gatsby develop via your npm scripts and monitor the console. If you have settings for Graph API set, then you may see the fallback message if it fails to connect. This is what I saw each time:

  warn Could not get instagram posts using the Graph API. 
  Error status Error: Request failed with status code 400
  warn Falling back to public scraping... with 1234567892

Render the results

Assuming you've named your react component or gatsby-node as 'instagram', we can now navigate to the path: http://localhost:8000/instagram/.

If you are facing issues, double check your routing and gatsby-config. In my case, I needed to free up the instagram path due to how strict this project is regarding unwanted path creation.

On loading the page, you'll see the instagram posts for the user you're targetting:

rendered instagram posts

Check out my example here: Instagram Gatsby Page

Conclusion

In the end, this library does what it says on the tin. However, I think we would have more options and more resilient retrieval if we could incorporate the Graph API. It would make things even easier to have a premium account from what I understand. I'll be reading up on how free accounts can use facebook apps and hope to revisit with a future blog post where I address the issues faced here.

Hope this was helpful.


Loading...

© Copyright 2023 Nathan Phennel