Search code examples
google-apps-scriptgoogle-drive-apiinstagram-graph-api

How to convert Google drive image into correct format to post it on Instagram using Google Apps Script?


I want to post images on Instagram, and for that, I followed a well-detailed StackOverflow answer. The images which I am trying to post on Instagram are coming from my Google drive folder (publicly shared). The code looks like this:

function instapost() {
  const access_token = '########....######';
  const instagram_business_account = '########';

  const image = 'https://drive.google.com/uc?export=view&id=1SNy876_kwrFBUCZdGfPLaKx6ZdKtYwn0';
  const text = 'subtitle';
  var formData = {
    'image_url': image,
    'caption': text,
    'access_token': access_token
  };
  var options = {
    'method' : 'post',
    'payload' : formData
  };
  const container = 'https://graph.facebook.com/v14.0/' + instagram_business_account + '/media';
  // return;
  const response = UrlFetchApp.fetch(container, options);

  const creation = response.getContentText();
  var data = JSON.parse(creation);
  var creationId = data.id
  var formDataPublish = {
      'creation_id': creationId,
      'access_token': access_token
  };
  var optionsPublish = {
    'method' : 'post',
    'payload' : formDataPublish
  };
  const sendinstagram = 'https://graph.facebook.com/v14.0/' + instagram_business_account + '/media_publish';
  
  UrlFetchApp.fetch(sendinstagram, optionsPublish);
}

When I run the script, I receive the following error:

Exception: Request failed for https://graph.facebook.com returned code 400. Truncated server response: {"error":{"message":"Only photo or video can be accepted as media type.","type":"OAuthException","code":9004,"error_subcode":2207052,"is_transient"... (use muteHttpExceptions option to examine full response)

I followed different sources (s1 - s2) to publicly access the G-Drive image but it is getting the same error every time, kindly can you guide me on how to convert this image so that it can be posted from Google Drive folder directly.


Solution

  • When I saw your provided official document, the values are required to be the query parameter. Ref But, in your script, the values are sent as form instead of the query parameter. I thought that this might be the reason for your current issue.

    When this is reflected in your script, how about the following modification?

    Modified script:

    function instapost() {
      // Ref: https://gist.github.com/tanaikech/70503e0ea6998083fcb05c6d2a857107
      String.prototype.addQuery = function (obj) {
        return this + Object.keys(obj).reduce(function (p, e, i) {
          return p + (i == 0 ? "?" : "&") +
            (Array.isArray(obj[e]) ? obj[e].reduce(function (str, f, j) {
              return str + e + "=" + encodeURIComponent(f) + (j != obj[e].length - 1 ? "&" : "")
            }, "") : e + "=" + encodeURIComponent(obj[e]));
        }, "");
      }
    
      const access_token = '########....######';
      const instagram_business_account = '########';
      const image = 'https://drive.google.com/uc?export=view&id=1SNy876_kwrFBUCZdGfPLaKx6ZdKtYwn0'; // or "https://drive.google.com/uc?id=1SNy876_kwrFBUCZdGfPLaKx6ZdKtYwn0&export=download"
      const text = 'subtitle';
      var query1 = {
        'image_url': image,
        'caption': text,
        'access_token': access_token
      };
      const container = 'https://graph.facebook.com/v14.0/' + instagram_business_account + '/media';
      const endpoint1 = container.addQuery(query1);
      const response = UrlFetchApp.fetch(endpoint1, { method: 'post' });
    
      const creation = response.getContentText();
      var data = JSON.parse(creation);
      var creationId = data.id
      var query2 = {
        'creation_id': creationId,
        'access_token': access_token
      };
      const sendinstagram = 'https://graph.facebook.com/v14.0/' + instagram_business_account + '/media_publish';
      const endpoint2 = sendinstagram.addQuery(query2);
      UrlFetchApp.fetch(endpoint2, { method: 'post' });
    }
    

    Note:

    • I think that the request for this modified script is the same as the sample HTTP requests of the official document you provided. But, unfortunately, I cannot test this script. So, when an error occurs, please confirm the values of query parameters and your access token again.

    • If your image URL cannot be used, please test the following URL. In this case, please enable Drive API at Advanced Google services.

        const image = Drive.Files.get("1SNy876_kwrFBUCZdGfPLaKx6ZdKtYwn0").thumbnailLink.replace(/\=s.+/, "=s1000");
      

    References: