Thursday, October 23, 2014

Making an R Package to use the HERE geocode API

HERE is a product by Nokia, formerly called Nokia maps and before that, Ovi maps. It's the result of the acquisition of NAVTEQ in 2007 combined with Plazes and Metacarta, among others. It has a geocoding API, mapping tiles, routing services, and other things. I'm focused on the geocoding service. Under the “Base” license, you can run 10,000 geocoding requests per day. According to wikipedia, that is the most among the free geocoding services. On top of that, HERE does bulk encoding where you submit a file of things to geocode and it returns a link to download a file of results. This sure beats making thousands of requests one at a time.

I figured coding up a quick function to use this service would be the perfect reason to build my first R package. So, after getting my HERE API keys, I fired up devtools and got started with the R package.

First, I had to install the latest version of devtools and roxygen2

install.packages("devtools", repos="")
install.packages("roxygen2", repos="")

Next, I chose a directory, and ran the create() function from devtools. This creates a package skeleton that contains the basic structure needed for an R package.


Several files and directories are created after running create(). I moved over to the 'R' directory and created a file called “geocodeHERE_simple.R”. I put my function to use the HERE geocoding API in there. This function was designed to be minimalist and similar to the ggmap geocode() function.

#' Attempt to geocode a string
#' Enter a string and have latitude and longitude returned using the HERE API
#' @param search A string to search
#' @param App_id App_id to use the production HERE API. Get one here... If left blank, will default to demo key with an unknown usage limit.
#' @param App_code App_code to use the production HERE API. Get one here... If left blank, will default to demo key with an unknown usage limit.
#' @keywords geocode
#' @export
#' @examples
#' \dontrun{
#' geocodeHERE_simple("chicago")
#' geocodeHERE_simple("wrigley field chicago IL")
#' geocodeHERE_simple("233 S Wacker Dr, Chicago, IL 60606")
#' }
#' geocodeHERE_simple
geocodeHERE_simple <- function(search, App_id="", App_code=""){
  if(!is.character(search)){stop("'search' must be a character string")}
  if(!is.character(App_id)){stop("'App_id' must be a character string")}
  if(!is.character(App_code)){stop("'App_code' must be a character string")}

  if(App_id=="" & App_code==""){
    App_id <- "DemoAppId01082013GAL"
    App_code <- "AJKnXv84fjrb0KIHawS0Tg"
    base_url <- ""
    base_url <- ""

  search <- RCurl::curlEscape(search)

  final_url <- paste0(base_url, format, "?app_id=", ids$App_id, "&app_code=",
                      ids$App_code, "&searchtext=", search)

  response <- RCurl::getURL(final_url)
  response_parsed <- RJSONIO::fromJSON(response)
  if(length(response_parsed$Response$View) > 0){
    ret <- response_parsed$Response$View[[1]]$Result[[1]]$Location$DisplayPosition
    ret <- NA

Note the text on the top of the code. That is added in order to automatically create help documentation for the function.

Now, if you look closely, I am using two other packages in that function… RCurl and RJSONIO. Also, notice that I'm not making any library() calls. This must be done in the DESCRIPTION file that is automatically generated by create(). In addition to calling out what packages to import, you input the package name, author, description, etc.

Package: geocodeHERE
Title: Wrapper for the HERE geocoding API
Version: 0.1
Authors@R: "Cory Nissen <> [aut, cre]"
Description: Wrapper for the HERE geocoding API
    R (>= 3.1.1)
License: MIT
LazyData: true

Then, I set my working directory to the package root and ran the document() function from devtools that automatically creates package documentation.


From this point, you can upload your package to github and use install_github(), or use the install() function to install your package locally.


As far as the HERE geocoding API goes, I find it pretty decent at doing “fuzzy matching”. That is, given a place name instead of an address, it does a good job of correctly returning the coordinates. The downside is that you must register for an API key, where Google does not require registration to use it's geocoding service. But, you only get 2500 requests per day via Google, HERE offers 10,000 per day.

Any how, a big shout out to Hilary Parker for her blog post on creating an R package using devtools, Hadley Wickham for the devtools package (among others), and RStudio for the fantastic and free (and open source) IDE for R.

The geocodeHERE package is available on github. I'll be adding bulk geocoding functionality as time permits. You can install the package with the following code:

geocodeHERE_simple("wrigley field chicago il")


  1. Hello,
    I would really like to know, what difference does it make, if you assign the default values for your function using "if" statement, instead of using function(search = "default", App_id="defaultID", App_code="defaultCode").

    Thanks in advance and thanks for the article! :)

    1. The app_id and app_code are given to you when you register an app with HERE. If you don't register, you can still use the API with the demo key, which is what is used if App_id and App_code are ""

  2. Hi Cory,
    Nice post thank you,
    Was trying your example URL (using the demo keys) as generated by your script but get a 404 page. Is it possible these ids are no longer valid?


    1. Can you re-download the package? I had made some changes that broke it, but it should be fixed now... Here's the working link for your query...

  3. I'm not getting anywhere in trying to set up a free account. It just says "Oops, something seems to have gone wrong. Please try again in a little while."

    1. If you don't have a key, the functions default to a set of "demo" keys that you can use to try out the service. I can't really help on the Nokia account set up stuff though.

    2. Okay, thanks. Maybe I'll figure out what is needed to get the keys for a free account.


Note: Only a member of this blog may post a comment.