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

Error: Cannot query field "display_url" on type "InstagramPhoto". #11

Open
nigelwhite opened this issue Jun 4, 2020 · 15 comments
Open

Comments

@nigelwhite
Copy link

Thanks for a great plugin. It has been working fine until the last few days.

It still works fine in development, but Netlify won't build any more. I get this error message in the Netlify output of the Netlify build attempt. Full error message is below.

The instance I am using is to query for 1 photo only.

I know Instagram have been changing their API - making it a million times harder to use. So I wanted to compare notes with you. Is the plugin still working for you? Or do we all have to look for an alternative solution?

Best wishes
Nigel


4:38:14 PM: Error: Cannot query field "display_url" on type "InstagramPhoto".
4:38:14 PM: GraphQL request:69:9
4:38:14 PM: 68 | id
4:38:14 PM: 69 | display_url
4:38:14 PM: | ^
4:38:14 PM: 70 | taken_at_timestamp
4:38:14 PM: at throwError (/opt/build/repo/node_modules/gridsome/lib/app/build/executeQueries.js:21:13)
4:38:14 PM: at pMap (/opt/build/repo/node_modules/gridsome/lib/app/build/executeQueries.js:41:11)
4:38:14 PM: at Promise.resolve.then.element (/opt/build/repo/node_modules/p-map/index.js:47:21)

@zefman
Copy link
Owner

zefman commented Jun 4, 2020

Hey @nigelwhite Thanks for this, yes I have noticed this problem too. Weirdly it seems to be intermittent sometimes and running the build again straight after fixes the problem.

So the way this plugin gets the image data is actually quite hacky, it loads a user's public profile and then parses the HTML and loads a JSON file that contains data about their most recent images. This is how the Gatsby Instagram plugin worked too so but I always knew it could break.

The error you are actually seeing is because for some reason the plugin didn't find any images so it thinks you are querying for a field that doesn't exist.

I will do some investigating and see if I can find the route cause.

@nigelwhite
Copy link
Author

Brilliant thanks.

I noticed a strange thing, before my instance broke.... I was able to get a whole Gallery of recent images from my client's Instagram feed. These also built ok in Netlify. So the plugin exceeded its spec! When Netlify stopped building, my first hypothesis was that I was breaking it by asking it for more images than one. So I removed the Gallery feature and went back to querying for only one image. That didn't fix the Netlify build.

Good luck

@zefman
Copy link
Owner

zefman commented Jun 4, 2020

Seems to be the same issue the gatsby plugin is having here: oorestisime/gatsby-source-instagram#131

The problem seems to be that Instagram are throwing up a login page for certain IPs. That's why it works locally but not on Netlify.

@zefman
Copy link
Owner

zefman commented Jun 4, 2020

I have tried a few things this evening to see if I could get around this.

  • Use a proxy server to get the data. This didn't work, probably because I deployed the server to Heroku and I suspect these Heroku IPs are in the list that Instagram has blocked.
  • Use puppeteer to login with a username and password and then get the profile data. This works fine locally, but again when it happens in the build agent Instagram change something to prevent you from getting the data.

It seems to only option might be for is to use their API with a token. I will need to look into what this involves.

@asefcamel
Copy link

Hello @zefman ,
first of all thank you for this awesome plugin.
I'm getting the same issue also, did you find something to fix this?

@MrMacStripe
Copy link

FYI The guys over at the Gatsby plugin seem to have worked it out with another approach.

@zefman
Copy link
Owner

zefman commented Jun 8, 2020

Hey, I will look at the Gatsby plugin to see how their solution works.

It might be that we have to add token-based authentication. Going forward that will probably be the only 100% reliable way to keep this working. It's a pain to setup though!

@nigelwhite
Copy link
Author

Thanks for looking into it. I agree the token-based authentication looks a real pain. I dunno if I could ever lead my client though that.

@MrMacStripe
Copy link

I found another alternative that works in a simple html site test setup. but I cant get it to work in Gridsome - I think I am misunderstanding how to use external scripts ...

https://github.com/jsanahuja/InstagramFeed

Maybe, if this is another approach, this can be implemented into the plugin?

I agree that it's really not ideal to deal with the API tokens and clients.

@ahoiadigital
Copy link

I'm having the same issue.

@MrMacStripe Did you manage to get https://github.com/jsanahuja/InstagramFeed to work on your Gridsome site?

@realgoatish
Copy link

realgoatish commented Jun 20, 2020

Hey @nigelwhite @MrMacStripe @ahoiadigital -

I ran into the same issue. Spent yesterday debugging and trying some possible fixes. Not sure if you're all using Netlify, but it definitely seems like Netlify's servers have been put on a blacklist for scraping IG's frontend the old-fashioned way. Maybe lots of people have been doing client-side scraping in their builds in a variety of projects.

The other lib that @MrMacStripe linked to gave me the idea of just doing it as an async client-side data call, at least for the time being until this plugin can be fixed. I too was unable to get that lib working on Gridsome, but then I realized it's much easier to just do exactly what this plugin does in a more compact way via the mounted hook, e.g.

<template>
  <div v-if="photos">
    <div v-for="(post, index) in photos.edges"
      :key="index">
       <a :href="`https://www.instagram.com/p/${post.node.shortcode}/`">
         <img
           :src="post.node.display_url"
           :alt="post.node.accessibility_caption"
         />
       </a>
     </div>
   </div>
</template>

................

<script>

import axios from 'axios'

export default {
    name: 'Footer',
    data () {
      return {
        photos: null
      }
    },
    async mounted () {
      try {
        const igProfileJson = await axios.get(
          `https://www.instagram.com/YOUR_INSTAGRAM_USERNAME/?__a=1`
        )
        this.photos = igProfileJson.data.graphql.user.edge_owner_to_timeline_media

        // might want to log this during your testing so you can see the object you need to traverse
        console.log(this.photos)
      } catch (error) {
        console.log(error)
      }
    }
  }
}

Note that I'm appending ?__a=1 to the Instagram URL because that gives you a straight JSON response of the user's profile data. It just makes for less wrangling you have to do with the response from the Axios call.

This response gives you their full profile data object, containing 12 images. If you only want 6 for example, you can just use standard array methods e.g.

const igProfileJson = await axios.get(
  `https://www.instagram.com/YOUR_INSTAGRAM_USERNAME/?__a=1`
)
igProfileJson.data.graphql.user.edge_owner_to_timeline_media.edges.splice(6, 6)
this.photos = igProfileJson.data.graphql.user.edge_owner_to_timeline_media

It's also worth noting that doing it this way gives you access to a fuller spectrum of profile data and not just the images array. This opens up the full range of data-usage possibilities from the other Lib that MrMacStripe linked to https://github.com/jsanahuja/InstagramFeed

Obviously you lose the benefit of having it in your GraphQL data layer. But you're still just querying JSON, so it can be handled in much the same way in your template code. If Netlify's servers are somehow blacklisted (at least as far as normal non-API-authed scrapes go), this seems like a good case for pushing the behavior to the client - again, at least until maybe this plugin can come up with a more durable fix.

@nigelwhite
Copy link
Author

@mflamb thank you for documenting your solution so carefully. It looks neat.

I think I have everything right. All I did is copy your code and put my friend's name in YOUR_INSTAGRAM_USERNAME. But I am getting nothing logged to the console and [Vue warn]: Property or method "photos" is not defined on the instance but referenced during render. Make sure that this property is reactive, either in the data option, or for class-based components, by initializing the property. That's strange as we can see we have data of photos: null.

I am in Gridsome. Axios is in my package.json and I am importing it in main.js.

@snikidev
Copy link

snikidev commented Jul 29, 2020

Just for the record, I'm building with Vercel, my build fails there as well, so it's not just Netlify. I get the same

Error: Cannot query field "display_url" on type "InstagramPhoto".
--
GraphQL request:27:9
       node {
         display_url
         ^
         edge_media_to_caption {

@asefcamel
Copy link

@mflamb thank you for documenting your solution so carefully. It looks neat.

I think I have everything right. All I did is copy your code and put my friend's name in YOUR_INSTAGRAM_USERNAME. But I am getting nothing logged to the console and [Vue warn]: Property or method "photos" is not defined on the instance but referenced during render. Make sure that this property is reactive, either in the data option, or for class-based components, by initializing the property. That's strange as we can see we have data of photos: null.

I am in Gridsome. Axios is in my package.json and I am importing it in main.js.

just paste this in the data, photos: { edges: {} }

@bytewise
Copy link

bytewise commented Jan 7, 2021

<template>
  <div v-if="photos">
    <div v-for="(post, index) in photos.edges"
      :key="index">
       <a :href="`https://www.instagram.com/p/${post.node.shortcode}/`">
         <img
           :src="post.node.display_url"
           :alt="post.node.accessibility_caption"
         />
       </a>
     </div>
   </div>
</template>

................

<script>

import axios from 'axios'

export default {
    name: 'Footer',
    data () {
      return {
        photos: null
      }
    },
    async mounted () {
      try {
        const igProfileJson = await axios.get(
          `https://www.instagram.com/YOUR_INSTAGRAM_USERNAME/?__a=1`
        )
        this.photos = igProfileJson.data.graphql.user.edge_owner_to_timeline_media

        // might want to log this during your testing so you can see the object you need to traverse
        console.log(this.photos)
      } catch (error) {
        console.log(error)
      }
    }
  }
}

@letslamb i'm trying out your solution but i get the error message :

TypeError: igProfileJson.data.graphql is undefined

I've implemented the code as in your example. So i'm wondering, is this still working for you? Or am i doing something wrong?

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

No branches or pull requests

8 participants