Tweet old posts from a feed using Google Apps Script

This article will show you how to create a simple twitter app using Google Apps Script to randomly tweet posts from any specified feed URL. For example, it can be scheduled to automatically tweet a random article from your blog once a day. If you have a WordPress blog, then another solution is to use the Tweet Old Post plugin. However, no such plugin or gadget exists for Blogger, which is what prompted me to write this article. In addition, you can use this solution to post random articles from any feed for which you have the URL.

Here's the steps
  1. Copy the Google Spreadsheet that contains the sample code
  2. Register a new application with Twitter
  3. Update the sample code with your feed URL and twitter keys
  4. Test the application and optionally schedule it to run automatically

Copy the Google Spreadsheet that contains the sample code

The sample code is in a script in a public google spreadsheet. Copy the spreadsheet. This link will open a new window. Click "Yes" when it prompts you to make a new copy of the document.

Register a new application with Twitter

Before you can tweet, you'll need to register a new application with Twitter. This will give you two strings that you will add to the sample code - consumer_key and consumer_secret. Once you have done this you'll be able to authorize the sample code to post to twitter on your behalf.

Visit the Twitter Developer site and create a new application. You'll need to login with your twitter account. Then you'll need to give your application a unique name, like "Tweet my_blog_domain.com", and a description. For "website" you can include your blog home page, or a page or article on your blog that describes what the application does. For the Callback URL you must specify "https://script.google.com/macros".

Before you can click "Create your twitter application" you'll also need to agree to the terms and conditions and answer a captcha. Once you have done this you'll receive a message that your application has been created. You need to change one setting for the application. By default the application is read-only. Which means it can't post a tweet on your behalf. From the settings tab change the application type access from read-only to read-write, and click the Update button.

Now go to the Details tab and find the strings alongside "Consumer key" and "Consumer secret" which you'll need in the next step.

Update the sample code with your feed URL and twitter keys

Open the copy of the spreadsheet that you created in the first step, and go to Tools > Script editor. At the top of the sample code you should see three variables that you need to change. The first is the URL for the feed that you want to post. The example I include is the feed for Google's official blog. You may want to test with this feed first before replacing it later with your own feed.

The next two variables are consumer_key and consumer_secret. Replace the values in the sample code with the values you received when you created a twitter application in the second step. Now click save.

Test the application and optionally schedule it to run automatically

Now you're ready to test your application. On the toolbar, pick "start" in the pull-down field which shows "Select function". Now click the run button. The first time you run the application you will receive an error message warning you "Error: Authorize at URL: ...". Click the "Details" button to see the full URL, and cut/paste this into a browser window, and you will be taken to a Twitter page which will prompt you to authorize your application to use your account. You need to click "Authorize App".

Once you have authorized the app with Twitter, go back and re-run the start function. This time you will receive a warning from Google, and will need to authorize the application with them. If all has gone well then in a few moments a tweet will appear in your twitter account showing the title and link to a random article from the feed. If nothing appears, then go back to the Script Editor and click View Logs. If there was an error it should show here. Try running the start function again and check the logs again. Other things to check are the values you copied for the consumer_key, consumer_secret and the feed url. 

Once you have it working you can optionally schedule it to run at certain times and days. To do this, click the "Current project's triggers" button on the toolbar and then the link to create a new trigger. Choose "start" in the first field, and "Time-driven" in the second field. You can now define any schedule, for example, pick "Day timer" and "Noon-1pm" to have the application post one article a day sometime between noon and 1pm.

Conclusion

This is a simple example of how to create a Twitter Application with Google Apps Script to tweet old posts from a feed such as a Blogger blog. The tweets created just contain the article title and url. There are many ways it could be improved. For example, you could read the article labels from the feed and include these in the tweet as hashtags, by modifying the readFeed function. It could also use the Google Apps Script UrlShortener service, by modifying the makeTweet function. But hopefully it provides a base sample from which you can build.

If you find this article useful, or run into any problems, then please post a comment below.

Note: Sample code updated to use the new OAuth1 library, since Google has deprecated the old OAuth approach.

27 comments:

  1. Hi! Thank you for this! Finally found a solution for my Blogger website!

    Anyway, can I do the same for Tumblr? I tried to make one, too, but only results to an error:

    TypeError: Cannot call method "getChild" of undefined. (line 32, file "Code")

    I did exactly the same way as instructed and I have the right RSS feed URL but can't get through. Appreciate your response! Thanks!

    ReplyDelete
    Replies
    1. It should work with any site that can generate an Atom XML format feed. It won't work with an RSS format feed. The error is saying that it couldn't find a 'title' element inside an 'entry' element. That's because the RSS format has the 'title' inside an 'item' element. The program could be changed to work with RSS, but it's probably easier to work out how to get an Atom feed from Tumblr.

      Delete
  2. Hi. I've been looking for an app like this. Need to explore it more, like what do i do if want to exclude posts (with certain labels) to be tweeted (is there a way to do that?) but basically, I'm just glad that I found this. Thanks alex!

    ReplyDelete
    Replies
    1. You can access the labels which show up as categories in the Atom feed. You could add something like the following after the code that retrieves the title

      var categoryElements = entries[i].getChildren('category', atom);
      var labels = [];
      for (var j = 0; j < categoryElements.length; j++) {
      labels.push(categoryElements[j].getAttribute('term').getValue());
      }

      You'll need to do more to then exclude certain posts based on the label, but this should get you started.

      Delete
    2. This comment has been removed by the author.

      Delete
    3. Hi, thank you for the replies. I wanna rephrase my question above: What if I wanna tweet only posts with labels say, "poetry", -- can you point that out to me on the code above? Thanks in advance :D

      Delete
    4. Hi Michael - although I'm sure it's possible to do in code, it would take me some time to figure it out. The code above extracts all the labels for a given post, but you would need to do this for all the posts in the feed, and then randomly pick from only those posts which contain the label you desire.

      A much more straightforward approach, would be to change the feed URL on line 4 to only return the posts for the label you are interested in. In the example code for this post you could change the URL to:

      http://googleblog.blogspot.com/feeds/posts/summary/-/mobile

      which would return only those posts which have the "mobile" label. Different blog platforms are going to have different URLs, but most of them are going to have some way to filter down the posts by a label.

      Delete
    5. Thanks Alex. That's what I actually did for my other blog but will it pull even old posts under the specified category? Anyway, will constantly visit this post for any update. Thank you so much for your help. Both of my blogs (yourlooktoday.com and thepinoywanderer.blogspot.com) are now using this app. Thanks to you!

      More power!

      Delete
    6. I _think_ by default the blogger feed url returns the last 25 posts. To increase that you can add "?max-results=500" to the URL.

      Delete
  3. Some follow up question:
    1) I got 2 blogs, how do i tweet old posts from both blogs through the same twitter account?
    2) Is there a way for me to exclude some posts? I've got posts about news that are current a year ago, not really OK if i broadcast them now, right? LOL

    Thanks in advance!

    ReplyDelete
    Replies
    1. 1) Simplest way is just to create two copies of the spreadsheet and script, and create two twitter applications so you have two twitter keys and secrets. Then each script can post from one of the blogs.

      2) Simplest way might be to use a URL which selects only the last X posts on your blog or all the posts since a certain date. How easy (or possible) this is depends on what blog site you are using. Can also be done through code, perhaps based on labels.

      Delete
  4. Could you PLEASE post the code with the Google Apps Script UrlShortener on it? I have no idea how to do it and i really need it.

    ReplyDelete
    Replies
    1. Here's the function I use for url shortening


      function shortenUrl(permalink) {
      var toShorten = UrlShortener.newUrl().setLongUrl(permalink + "?utm_source=retweeter&utm_medium=twitter&utm_campaign=from+the+archives");
      var shortened = UrlShortener.Url.insert(toShorten);
      return shortened.getId();
      }

      This also adds campaign tracking codes to the url for google analytics, but you can easily remove that addition.

      Delete
    2. This is the code for the app im using:

      var FEED_URL = "http://feeds.feedburner.com/ResistenciaNoticias";

      var CONSUMER_KEY = "XXXXXXXXXXXXX";
      var CONSUMER_SECRET = "XXXXXXXXX";

      function start() {
      var tweet = readFeed();
      postTweet(tweet);
      Logger.log("Done.");
      }

      function readFeed() {
      Logger.log("Feed URL: %s", FEED_URL);
      var xml = UrlFetchApp.fetch(FEED_URL).getContentText();
      var document = XmlService.parse(xml);
      var root = document.getRootElement();
      var atom = XmlService.getNamespace('http://www.w3.org/2005/Atom');
      var entries = document.getRootElement().getChildren('entry', atom);

      var i = Math.floor(Math.random() * entries.length);
      Logger.log("Tweeting entry %s out of %s", i, entries.length);

      // Get the title and permalink from the article
      var title = entries[i].getChild('title', atom).getText();
      var linkElements = entries[i].getChildren('link', atom);
      var permalink = '';
      for (var k = 0; k < linkElements.length; k++) {
      if (linkElements[k].getAttribute('rel').getValue() == 'alternate') {
      permalink = linkElements[k].getAttribute('href').getValue();
      }


      }

      var tweet = makeTweet(title, permalink);
      Logger.log("Tweet: %s", tweet);
      return tweet;
      }

      function makeTweet(title, permalink) {
      // max tweet length is 140, all urls count as 22 characters, plus we need a space
      // if title is too long, then truncate it and put "..." at the end
      if (title.length > 140 - 22 - 1) {
      title = title.substring(0, 140 - 22 - 1 - 3) + "...";
      var url = UrlShortener.Url.insert({
      longUrl: 'http://www.example.com'
      }
      ) }
      return title + " " + permalink;
      }

      function shortenUrl(permalink) {
      var toShorten = UrlShortener.newUrl().setLongUrl(permalink + "?utm_source=retweeter&utm_medium=twitter&utm_campaign=from+the+archives");
      var shortened = UrlShortener.Url.insert(toShorten);
      return shortened.getId();
      }

      /* Workaround for https://code.google.com/p/google-apps-script-issues/issues/detail?id=3046 */
      function patchTweet(tweet){
      tweet = tweet.replace(/!/g,'.');
      tweet = tweet.replace(/\*/g,'x');
      tweet = tweet.replace(/\(/g,'<');
      tweet = tweet.replace(/\)/g,'>');
      tweet = tweet.replace(/'/g,'`');
      return tweet;
      }

      function postTweet(tweet) {
      authorize();
      var encodedTweet = encodeURIComponent(patchTweet(tweet));
      var requestData = {
      "method": "POST",
      "oAuthServiceName": "twitter",
      "oAuthUseToken": "always"
      };
      try {
      var result = UrlFetchApp.fetch(
      "https://api.twitter.com/1.1/statuses/update.json?status=" + encodedTweet, requestData);
      } catch (e) {
      Logger.log(e);
      }
      }

      function authorize() {
      var oauthConfig = UrlFetchApp.addOAuthService("twitter");
      oauthConfig.setAccessTokenUrl("https://api.twitter.com/oauth/access_token");
      oauthConfig.setRequestTokenUrl("https://api.twitter.com/oauth/request_token");
      oauthConfig.setAuthorizationUrl("https://api.twitter.com/oauth/authorize");
      oauthConfig.setConsumerKey(CONSUMER_KEY);
      oauthConfig.setConsumerSecret(CONSUMER_SECRET);
      var requestData = {
      "method": "GET",
      "oAuthServiceName": "twitter",
      "oAuthUseToken": "always"
      };
      try {
      var result = UrlFetchApp.fetch(
      "https://api.twitter.com/1.1/statuses/mentions_timeline.json",
      requestData);
      } catch(e) {
      Logger.log(e);
      }
      }

      The shorten urls are not showing. Please help

      Delete
    3. Is everything posting ok and just not the urls? If so, then try replacing the following code


      var url = UrlShortener.Url.insert({
      longUrl: 'http://www.example.com'
      }
      ) }
      return title + " " + permalink;


      with


      var url = shortenUrl(permalink);
      return title + " " + url;

      Delete
    4. I did. Now it says "ReferenceError: "postTweet" is not defined. (line 14, archive "Code")".
      Yeah everything im posting looks fine but the URLs.

      Delete
    5. I think there's a missing } in makeTweet before the line beginning var url =

      Delete
  5. HI! Help! Tweet Old Post has stopped working and as I read along it says,

    Script is using OAuthConfig which has been shut down. Learn more at http://goo.gl/IwCSaV (line 82, file "Code")

    help? I tried following tutorials but I must be missing something. It keeps resulting to errors. Thank yoouuuu!

    ReplyDelete
    Replies
    1. I have updated the same code to use the new OAuth1 library. If you click the link in the post you should get a copy of the new spreadsheet and can either update this with your own consumer key/secret and blog URL, or cut/paste the revised code across into your script. Notice, I've moved most of the twitter functions into a separate Twitter.gs script file. Good luck.

      Delete
    2. Dear Alex, why do we get the Error-message
      Error: Authorize at URL: https://api.twitter.com/oauth/authorize?oauth_token=1UkcGAAAAAAAVkYDAAABT1HWJKg (line 60, file "")
      as we try to run "start" after all the updates in the spreadsheet?

      Delete
    3. This is a message from Twitter to let you know that you need to authorize the application with your Twitter credentials before it will work. You need to click the link (or cut/paste the link into a browser window), login with the twitter account you are using, and click the Authorize button. Once you have done this once, it will not give you this message again next time you run "start".

      Delete
    4. THANK YOU !!!!!!!!!! it works again :)
      have a great week :)

      Delete
  6. Hey! IS there a way your code could read the feed title right? I mean it reads () as <> and ! as .

    Thank you this was soo helpful you have no idea.

    ReplyDelete
    Replies
    1. This is caused by the patchTweet() function in Common.gs and is to work around a bug that Google has. There's more information about the bug here https://code.google.com/p/google-apps-script-issues/issues/detail?id=3046

      There's a comment from Apr 30, 2014 on that bug which looks worth trying. If anyone has any luck with it, let me know and I'll update the code in this post.

      Delete
  7. Hello, I am really sorry to be such a techno wally but how do i disable this? I am scared I am going to delete something awful if i try and do it myself? I've stopped blogging so i want my auto tweets to stop on my twitter account.

    ReplyDelete
    Replies
    1. Two ways. The simplest is just to delete the spreadsheet. If instead you just want to disable it but might want to use it in future then you'll want to just delete the trigger that is running the script on a schedule. Here are the steps:

      1. open your copy of the spreadsheet
      2. click Tools > Script editor...
      3. click Resources > Current project's triggers
      4. click the X alongside the trigger (or triggers if you setup multiple)
      5. click save
      6. close the browser tab containing the script editor

      Delete