Skip navigation

@mkjcktzn asked if one can access Feedly “Saved for Later” items via the API. The answer is “Yes!”, and it builds off of that previous post. You’ll need to read it and get your authentication key (still no package ?) before continuing.

We’ll use most (I think “all”) of the code from the previous post, so let’s bring that over here:

library(httr)
library(tidyverse)

.pkgenv <- new.env(parent=emptyenv())
.pkgenv$token <- Sys.getenv("FEEDLY_ACCESS_TOKEN")

.feedly_token <- function() return(.pkgenv$token)

feedly_stream <- function(stream_id, ct=100L, continuation=NULL) {
  
  ct <- as.integer(ct)
  
  if (!is.null(continuation)) ct <- 1000L
  
  httr::GET(
    url = "https://cloud.feedly.com/v3/streams/contents",
    httr::add_headers(
      `Authorization` = sprintf("OAuth %s", .feedly_token())
    ),
    query = list(
      streamId = stream_id,
      count = ct,
      continuation = continuation
    )
  ) -> res
  
  httr::stop_for_status(res)
  
  res <- httr::content(res, as="text")
  res <- jsonlite::fromJSON(res)
  
  res
  
}

According to the Feedly API Overview there is a “global resource id” which is formatted like user/:userId/tag/global.saved and defined as “Users can save articles for later. Equivalent of starring articles in Google Reader.”.

The “Saved for Later” feature is quite handy and all we need to do to get access to it is substitute our user id for :userId. To do that, we’ll build a helper function:

feedly_profile <- function() {
  
  httr::GET(
    url = "https://cloud.feedly.com/v3/profile",
    httr::add_headers(
      `Authorization` = sprintf("OAuth %s", .feedly_token())
    )
  ) -> res
  
  httr::stop_for_status(res)
  
  res <- httr::content(res, as="text")
  res <- jsonlite::fromJSON(res)
  
  class(res) <- c("feedly_profile")
  
  res
  
}

When that function is called, it returns a ton of user profile information in a list, including the id that we need:

me <- feedly_profile()

str(me, 1)
## List of 46
##  $ id                          : chr "9b61e777-6ee2-476d-a158-03050694896a"
##  $ client                      : chr "feedly"
##  $ email                       : chr "...@example.com"
##  $ wave                        : chr "2013.26"
##  $ logins                      :'data.frame': 4 obs. of  6 variables:
##  $ product                     : chr "Feedly..."
##  $ picture                     : chr "https://..."
##  $ twitter                     : chr "hrbrmstr"
##  $ givenName                   : chr "..."
##  $ evernoteUserId              : chr "112233"
##  $ familyName                  : chr "..."
##  $ google                      : chr "1100199130101939"
##  $ gender                      : chr "..."
##  $ windowsLiveId               : chr "1020d010389281e3"
##  $ twitterUserId               : chr "99119939"
##  $ twitterProfileBannerImageUrl: chr "https://..."
##  $ evernoteStoreUrl            : chr "https://..."
##  $ evernoteWebApiPrefix        : chr "https://..."
##  $ evernotePartialOAuth        : logi ...
##  $ dropboxUid                  : chr "54555"
##  $ subscriptionPaymentProvider : chr "......"
##  $ productExpiration           : num 2.65e+12
##  $ subscriptionRenewalDate     : num 2.65e+12
##  $ subscriptionStatus          : chr "Active"
##  $ upgradeDate                 : num 2.5e+12
##  $ backupTags                  : logi TRUE
##  $ backupOpml                  : logi TRUE
##  $ dropboxConnected            : logi TRUE
##  $ twitterConnected            : logi TRUE
##  $ customGivenName             : chr "..."
##  $ customFamilyName            : chr "..."
##  $ customEmail                 : chr "...@example.com"
##  $ pocketUsername              : chr "...@example.com"
##  $ windowsLivePartialOAuth     : logi TRUE
##  $ facebookConnected           : logi FALSE
##  $ productRenewalAmount        : int 1111
##  $ evernoteConnected           : logi TRUE
##  $ pocketConnected             : logi TRUE
##  $ wordPressConnected          : logi FALSE
##  $ windowsLiveConnected        : logi TRUE
##  $ dropboxOpmlBackup           : logi TRUE
##  $ dropboxTagBackup            : logi TRUE
##  $ backupPageFormat            : chr "Html"
##  $ dropboxFormat               : chr "Html"
##  $ locale                      : chr "en_US"
##  $ fullName                    : chr "..."
##  - attr(*, "class")= chr "feedly_profile"

(You didn’t think I wouldn’t redact that, did you? Note that I made up a unique id as well.)

Now we can call our stream function and get the results:

entries <- feedly_stream(sprintf("user/%s/tag/global.saved", me$id))

str(entries$items, 1)
# output not shown as you don't really need to see what I've Saved for Later

The structure is the same as in the previous post.

Now, you can go to town and programmatically access your Feedly “Saved for Later” entries.

You an also find more “Resource Ids” and “Global Resource Ids” formats on the API Overview page.

2 Comments

  1. This worked like a charm,

    I shoehorned in the while loop from part 1 to get all my saved items from out of the dungeon


2 Trackbacks/Pingbacks

  1. […] article was first published on R – rud.is, and kindly contributed to […]

  2. […] recent post was created to help someone use the API. It worked for them but — as you can see in the comment […]

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.