Instagram Feed - How to display your last X Insta Image

I recently created an Insta-Feed in my Frontity project, and I’m happy to share my solution.
I am a beginner with JS and React, so feel free to improve it and share your opinion.
As Instagram API seemed too complicated for me, and I did not find a simple solution to communicate with it, I used Zapier RSS feed instead. You can set up a Zap-Insta-feed, as described here.
I use react-fetch-hook to get my Feed.
So first, install react-fetch-hook:

npm i react-fetch-hook --save

And my <Instagram/> component looks like:

import React from 'react';
import useFetch from "react-fetch-hook";
import Image from '@frontity/components/image';
import Link from './link';

const Instagram = () => {
  var instaObjects = [];
  const { isLoading, data } = useFetch(
    "https://zapier.com/engine/rss/123456789/myZapFeed",
    {
      formatter: response => response.text()
    }
  );

  if (data){
    let instaObjects = [];
    const items = data.match(/<item>(.|\n)*?<\/item>/g).map(function(val) {
      return val.replace(/<\/?b>/g, "");
    });
    items.map((item, index) => {
      const title = /<title>(.|\n)*?<\/title>/.exec(item);
      const link = /<link>(.*?)<\/link>/.exec(item);
      const enclosure = /<enclosure (.*?)<\/enclosure>/.exec(item);
      const image = enclosure[1].match(/"((?:\\.|[^"\\])*)"/);
      const encodedImage = image[1].replace(/&amp;/g, "&");

      instaObjects.push({
        title: title[1],
        link: link[1],
        image: encodedImage,
      });
    });
    
    return (
      <>
        {instaObjects.map(({ title, link, image }, index) => {
          return (
            <Link key={index} link={link}>
              <Image src={image} alt={title} objectFit="cover" />
            </Link>
          );
        })}
      </>
    );
  }
 return "Loading";
};
export default Instagram;

I hope it helps some of you! :slight_smile:

5 Likes

Nice work @koli14! :slightly_smiling_face:

Just a quick feedback: you can use a hook for fetch like for example react-fetch-hook, because, in contrast to axios, fetch is included in the browser.

Bundlephobia is a great way to quickly check the size of an npm package.

Thanks for the feedback!
I edited my code and my original post, using now react-fetch-hook! :slight_smile:

Thanks a lot for your contribution @koli14!

@Reyes take a look, I think this could go on our next newsletter :blush:

1 Like

I have an ReferenceError: DOMParser is not defined at the moment if not running on Localhost but Zeit, but it will be fixed in hours…:stuck_out_tongue: @luisherranz do you have a Parser suggestion?

That was quick :slight_smile:

Where are you using the DOMParser? It’s not in the react-fetch-hook for what I can see, right?(https://github.com/ilyalesik/react-fetch-hook/search?q=DOMParser&unscoped_q=DOMParser)

With axios I could do the following:

const doc = response.request.responseXML;
const items = doc.getElementsByTagName('item');

But I could not do the same with react-fetch. It does have a Custom formatter, but I have no idea how to use it. In the docs it mentions a JSON formatter, and a text. My RSS feed gives back XML. So i choose text, and try to parse it with a parser.
First I did it like:

const parser = new DOMParser();
const doc = parser.parseFromString(data, "text/xml");
const items = doc.getElementsByTagName('item');

But it does not work on Zeit, only on localhost.

I edited my original post again, now I use Regexp to parse the XML string returned by react-fetch. I’m not a big regexp master, I hope it will be stable. Now it’s working.

Awesome :smile:

Wow, is the Instagram API still using XML instead of JSON?? :open_mouth:

No. I do not get the Insta Posts from Instagram but through Zapier RSS feed. Insta API was too complicated for me, and I did not find an easy-to-use and well-documented npm package for it.

Interesting, thanks.

Remember that a lot of times you can find an npm package that makes your life easier. For example, in this case, you could use something like this https://www.npmjs.com/package/simple-xml-to-json instead of regexps.

The only thing you need to make sure is that packages are small enough for client-side usage. A lot of times two package that can look alike can weight a lot more:

Thanks @luisherranz. Sadly https://www.npmjs.com/package/simple-xml-to-json is not working correctly. I created an issue about: https://github.com/nirgit/xml-to-json/issues/2
Yes, I also checked a lot of xml parser, but I did not found a working one, which was smaller then axios (which includes it).

Well yes, sadly sometimes that happens :laughing:

It’s just weird to see an XML API nowadays but no problem if it works :slight_smile:

I would be also happier if I could get back JSON. It’s definietly not the best solution, but I hope the community will find a better solution soon.

1 Like

IMORTANT: The method described above does not working anymore (since INSTAGRAM api changes).
I came up with a new solution, but I don’t find where can I edit my original post, so I write it here:
Insta has a api like:

https://www.instagram.com/graphql/query/?query_hash=42323d64886122307be10013ad2dcc44&variables={"id":"YOUR_INSTAGRAM_ID","first":8}

So you can fetch your InstaPosts like:

import useFetch from 'react-fetch-hook'
import Loading from './loading'
import Link from './link'
import Image from '@frontity/components/image'

const Instagram = ({ hideInsta }) => {
  const { data } = useFetch(
    'https://www.instagram.com/graphql/query/?query_hash=42323d64886122307be10013ad2dcc44&variables={"id":"YOUR_INSTAGRAM_ID","first":8}'
  )

  if (data) {
    const instaPosts = slimUpPosts(data)
    return (
      <>
        {instaPosts.map(({ caption, url, thumbnail, mobileDisplay }, index) => {
          return (
            <Link key={index} link={url}>
              <Image src={thumbnail} alt={caption} objectFit='cover' />
            </Link>
          )
        })}
      </>
    )
  }
  return <Loading />
}

function slimUpPosts (response) {
  return response.data.user.edge_owner_to_timeline_media.edges.map(({ node }, index) => {
    let caption = node.edge_media_to_caption.edges[0].node.text
    caption = caption.length > 120 ? caption.slice(0, 120) + '...' : caption
    return {
      thumbnail: node.thumbnail_src,
      url: `https://instagram.com/p/${node.shortcode}`,
      caption,
      id: node.id
    }
  })
}

is it possible to cache the response from Instagram?

2 Likes

Hi @koli14

That is great, thank you so much for doing that.

One thing I can’t figure out is how to get the Instagram query_hash. Would you be able to point me in the right direction please?

Thanks,
Jeff

Hey @jeff!
You can use the query hash from above. You just need your Insta ID.
About query hashs: Let Me Google That