Skip to contents

Overview

kbtbr is a wrapper for the KoBoToolbox APIs. It focuses on API v2 but also makes use of v1 if required.

kbtbr uses R6 classes. This means it has an object-oriented user interface which might feel unfamiliar to R users at first. But don’t worry - you should get used to it quickly!

Setup

Authentication

Get an API token using any of the methods described in the KoBoToolbox documentation. Then store it as an environment variable by opening and editing your .Renviron:

usethis::edit_r_environ()

Add your token on a new line as follows:

KBTBR_TOKEN=yourapitokenhere

Save the file and restart R/RStudio.

Of course, you can also use local environment files or any other method to securely store the API token.

Base URL

In order to use kbtbr, you need to know the base URLs of your KoBoToolbox server (cf. here). There are two base URLs, one for API version 2 and one for version 1. To use the kbtbr package, you only need to specify the base URL for version 2. However, certain functionalities that rely on the version 1 API will require its base URL.

If you are using one of the two hosted instances, those are the base URLs:

version Humanitarian Server (OCHA) Non-Humanitarian Server
v2 https://kobo.humanitarianresponse.info https://kf.kobotoolbox.org
v1 https://kc.humanitarianresponse.info https://kc.kobotoolbox.org

Creating the Kobo instance

With the right base URL(s), we can create an instance of the Kobo class. The base_url_v1 argument is optional.

library(kbtbr)
library(dplyr)
base_url_v2 <- "https://kobo.correlaid.org" # replace with your base URL for v2
base_url_v1  <- "https://kc.correlaid.org" # replace with your base URL for v1 
token <- Sys.getenv("KBTBR_TOKEN")

kobo <- Kobo$new(base_url_v2, base_url_v1, token)
kobo
## <Kobo>
##   Public:
##     clone: function (deep = FALSE) 
##     clone_asset: function (clone_from, new_name, asset_type) 
##     create_asset: function (name, asset_type, description = "", sector = list(label = "", 
##     deploy_asset: function (uid) 
##     get: function (path, query = list(), version = "v2", format = "json", 
##     get_asset: function (id) 
##     get_assets: function () 
##     get_submissions: function (id) 
##     get_surveys: function (show_all_cols = FALSE) 
##     import_xls_form: function (name, file_path) 
##     initialize: function (base_url_v2 = NULL, base_url_v1 = NULL, kobo_token = Sys.getenv("KBTBR_TOKEN"), 
##     post: function (path, body, version = "v2") 
##     session_v1: KoboClient, HttpClient, R6
##     session_v2: KoboClient, HttpClient, R6

For alternative ways of initializing the Kobo class, see here.

Working with the Kobo class

A good first step is to get an overview over all your assets. Almost everything in KoBoToolbox is an asset: questions, blocks, forms, templates.

assets <- kobo$get_assets()
table(assets$asset_type)
## 
##    block question   survey template 
##        9        4       45        7

You can also just get your forms/surveys:

surveys <- kobo$get_surveys()

Inspect the data manually:

head(surveys)
## # A tibble: 6 × 9
##   name    uid   date_created date_modified owner__username parent has_deployment
##   <chr>   <chr> <chr>        <chr>         <chr>           <chr>  <lgl>         
## 1 Test s… a27V… 2022-01-24T… 2022-01-24T1… api_user        NA     TRUE          
## 2 Test s… aCZ7… 2022-01-24T… 2022-01-24T1… api_user        NA     TRUE          
## 3 Test s… aXDf… 2022-01-24T… 2022-01-24T1… api_user        NA     FALSE         
## 4 Test s… apwD… 2022-01-24T… 2022-01-24T1… api_user        NA     FALSE         
## 5 clonin… aXLR… 2022-01-24T… 2022-01-24T1… api_user        NA     FALSE         
## 6 kbtbr … aRo4… 2021-05-02T… 2021-09-24T1… api_user        NA     TRUE          
## # … with 2 more variables: deployment__active <lgl>,
## #   deployment__submission_count <int>

You can then extract the ID of a single survey by filtering for its name.

test_id <- surveys %>% filter(name == "kbtbr Testing Survey") %>% pull(uid)

Get the answers (or submissions in KoBoToolbox API lingo) to the form/survey:

submissions <- kobo$get_submissions(test_id)
str(submissions)
## tibble [8 × 35] (S3: tbl_df/tbl/data.frame)
##  $ _id                                               : int [1:8] 482 484 485 486 487 532 647 659
##  $ control_over_life                                 : chr [1:8] "7" "3" "3" "3" ...
##  $ Taking_all_things_to_ould_you_say_you_are         : chr [1:8] "1" "3" "8" "3" ...
##  $ voluntary_activity                                : chr [1:8] "8" "8" "8" "2" ...
##  $ trust_in_groups/Your_family                       : chr [1:8] "1" "2" "1" "2" ...
##  $ formhub/uuid                                      : chr [1:8] "1f37921296654b91b8cc11e152956764" "1f37921296654b91b8cc11e152956764" "1f37921296654b91b8cc11e152956764" "1f37921296654b91b8cc11e152956764" ...
##  $ _validation_status                                :'data.frame':  8 obs. of  0 variables
##  $ importance_in_life/Politics                       : chr [1:8] "1" "3" "2" "3" ...
##  $ _uuid                                             : chr [1:8] "199a3066-72a2-48b0-ade1-c186ae6cb0e7" "199a3066-72a2-48b0-ade1-c186ae6cb0e7" "199a3066-72a2-48b0-ade1-c186ae6cb0e7" "199a3066-72a2-48b0-ade1-c186ae6cb0e7" ...
##  $ health_self_assessment                            : chr [1:8] "5" "3" "3" "5" ...
##  $ importance_in_life/Friends_and_acquaintances      : chr [1:8] "1" "2" "2" "3" ...
##  $ _tags                                             :List of 8
##   ..$ : list()
##   ..$ : list()
##   ..$ : list()
##   ..$ : list()
##   ..$ : list()
##   ..$ : list()
##   ..$ : list()
##   ..$ : list()
##  $ trust_in_groups/People_you_know_personally        : chr [1:8] "2" "2" "2" "3" ...
##  $ _submitted_by                                     : logi [1:8] NA NA NA NA NA NA ...
##  $ _xform_id_string                                  : chr [1:8] "aRo4wg5utWT7dwdnQQEAE7" "aRo4wg5utWT7dwdnQQEAE7" "aRo4wg5utWT7dwdnQQEAE7" "aRo4wg5utWT7dwdnQQEAE7" ...
##  $ importance_in_life/Family                         : chr [1:8] "2" "3" "1" "2" ...
##  $ trust_in_groups/People_you_meet_for_the_first_time: chr [1:8] "3" "2" "2" "3" ...
##  $ meta/instanceID                                   : chr [1:8] "uuid:199a3066-72a2-48b0-ade1-c186ae6cb0e7" "uuid:199a3066-72a2-48b0-ade1-c186ae6cb0e7" "uuid:199a3066-72a2-48b0-ade1-c186ae6cb0e7" "uuid:199a3066-72a2-48b0-ade1-c186ae6cb0e7" ...
##  $ trust_in_groups/People_of_another_nationality     : chr [1:8] "2" "3" "3" "2" ...
##  $ trust_in_groups/People_in_your_neighborhood       : chr [1:8] "3" "1" "2" "2" ...
##  $ importance_in_life/Religion                       : chr [1:8] "1" "3" "3" "2" ...
##  $ end                                               : chr [1:8] "2021-09-01T21:38:34.035+02:00" "2021-09-01T21:52:25.333+02:00" "2021-09-01T21:53:05.707+02:00" "2021-09-01T21:53:39.141+02:00" ...
##  $ locate_hamburg                                    : chr [1:8] "60.924739 -90.682977 0 0" "34.461879 -126.200905 0 0" "48.52047 70.320327 0 0" "64.520727 52.758186 0 0" ...
##  $ _submission_time                                  : chr [1:8] "2021-09-01T19:38:34" "2021-09-01T19:52:25" "2021-09-01T19:53:05" "2021-09-01T19:53:39" ...
##  $ _notes                                            :List of 8
##   ..$ : list()
##   ..$ : list()
##   ..$ : list()
##   ..$ : list()
##   ..$ : list()
##   ..$ : list()
##   ..$ : list()
##   ..$ : list()
##  $ _attachments                                      :List of 8
##   ..$ :'data.frame': 0 obs. of  0 variables
##   ..$ :'data.frame': 0 obs. of  0 variables
##   ..$ :'data.frame': 0 obs. of  0 variables
##   ..$ :'data.frame': 0 obs. of  0 variables
##   ..$ :'data.frame': 0 obs. of  0 variables
##   ..$ :'data.frame': 1 obs. of  9 variables:
##   .. ..$ mimetype           : chr "image/png"
##   .. ..$ download_small_url : chr "https://kc.correlaid.org/media/small?media_file=api_user%2Fattachments%2F1f37921296654b91b8cc11e152956764%2F40c"| __truncated__
##   .. ..$ download_large_url : chr "https://kc.correlaid.org/media/large?media_file=api_user%2Fattachments%2F1f37921296654b91b8cc11e152956764%2F40c"| __truncated__
##   .. ..$ download_url       : chr "https://kc.correlaid.org/media/original?media_file=api_user%2Fattachments%2F1f37921296654b91b8cc11e152956764%2F"| __truncated__
##   .. ..$ filename           : chr "api_user/attachments/1f37921296654b91b8cc11e152956764/40c70c77-7d3d-4824-8e0e-43094764a75d/Screenshot 2021-09-0"| __truncated__
##   .. ..$ instance           : int 532
##   .. ..$ download_medium_url: chr "https://kc.correlaid.org/media/medium?media_file=api_user%2Fattachments%2F1f37921296654b91b8cc11e152956764%2F40"| __truncated__
##   .. ..$ id                 : int 3
##   .. ..$ xform              : int 18
##   ..$ :'data.frame': 0 obs. of  0 variables
##   ..$ :'data.frame': 0 obs. of  0 variables
##  $ importance_in_life/Leisure_time                   : chr [1:8] "1" "2" "2" "3" ...
##  $ start                                             : chr [1:8] "2021-09-01T21:36:49.742+02:00" "2021-09-01T21:36:49.742+02:00" "2021-09-01T21:36:49.742+02:00" "2021-09-01T21:36:49.742+02:00" ...
##  $ trust_in_groups/People_of_another_religion        : chr [1:8] "2" "3" "3" NA ...
##  $ _geolocation                                      :List of 8
##   ..$ : num [1:2] 60.9 -90.7
##   ..$ : num [1:2] 34.5 -126.2
##   ..$ : num [1:2] 48.5 70.3
##   ..$ : num [1:2] 64.5 52.8
##   ..$ : num [1:2] 62.3 43
##   ..$ : num [1:2] 53.5 10
##   ..$ : num [1:2] -6.5 85
##   ..$ : num [1:2] 53.1 11.1
##  $ importance_in_life/Work                           : chr [1:8] "1" "2" "1" "2" ...
##  $ _status                                           : chr [1:8] "submitted_via_web" "submitted_via_web" "submitted_via_web" "submitted_via_web" ...
##  $ __version__                                       : chr [1:8] "vkhZEtuEwyhNgJropgVs7h" "vkhZEtuEwyhNgJropgVs7h" "vkhZEtuEwyhNgJropgVs7h" "vkhZEtuEwyhNgJropgVs7h" ...
##  $ trust_in_others                                   : chr [1:8] "2" "2" "2" "2" ...
##  $ file_upload                                       : chr [1:8] NA NA NA NA ...

Check out Data wrangling of responses to see how to handle messy column names.

Kobo Administration with kbtbr

With kbtbr, you can also manage your assets and do other useful administration tasks right from your R console.

Create an Asset

You can also create assets using the create_asset() method of the Kobo class. This can be useful if you need to create a lot of assets at once.

res <- kobo$create_asset("Question block", 
                  asset_type = "block", 
                  description = "this question block was created with the API.")
res$status_http()
## <Status code: 201>
##   Message: Created
##   Explanation: Document created, URL follows
response_content <- res$parse("UTF-8") %>% jsonlite::fromJSON()
str(response_content, max.level = 1)
## List of 39
##  $ url                            : chr "https://kobo.correlaid.org/api/v2/assets/avJyi8RUCjQ4RSFA7qdWPG/"
##  $ owner                          : chr "https://kobo.correlaid.org/api/v2/users/api_user/"
##  $ owner__username                : chr "api_user"
##  $ parent                         : NULL
##  $ ancestors                      : NULL
##  $ settings                       :List of 4
##  $ asset_type                     : chr "block"
##  $ date_created                   : chr "2022-01-24T13:24:29.331033Z"
##  $ summary                        : Named list()
##  $ date_modified                  : chr "2022-01-24T13:24:29.331054Z"
##  $ version_id                     : chr "vZpxcU8qvJ9N6wHSiPsSpv"
##  $ version__content_hash          : chr "4724ddb07034559d7fb5a3d18288dfb683a2d082"
##  $ version_count                  : int 1
##  $ has_deployment                 : logi FALSE
##  $ deployed_version_id            : NULL
##  $ deployed_versions              :List of 4
##  $ deployment__identifier         : NULL
##  $ deployment__links              : Named list()
##  $ deployment__active             : logi FALSE
##  $ deployment__data_download_links: Named list()
##  $ deployment__submission_count   : int 0
##  $ report_styles                  :List of 3
##  $ report_custom                  : Named list()
##  $ map_styles                     : Named list()
##  $ map_custom                     : Named list()
##  $ content                        :List of 3
##  $ downloads                      :'data.frame': 2 obs. of  2 variables:
##  $ embeds                         :'data.frame': 2 obs. of  2 variables:
##  $ koboform_link                  : chr "https://kobo.correlaid.org/api/v2/assets/avJyi8RUCjQ4RSFA7qdWPG/koboform/"
##  $ xform_link                     : chr "https://kobo.correlaid.org/api/v2/assets/avJyi8RUCjQ4RSFA7qdWPG/xform/"
##  $ hooks_link                     : chr "https://kobo.correlaid.org/api/v2/assets/avJyi8RUCjQ4RSFA7qdWPG/hooks/"
##  $ tag_string                     : chr ""
##  $ uid                            : chr "avJyi8RUCjQ4RSFA7qdWPG"
##  $ kind                           : chr "asset"
##  $ xls_link                       : chr "https://kobo.correlaid.org/api/v2/assets/avJyi8RUCjQ4RSFA7qdWPG/xls/"
##  $ name                           : chr "Question block"
##  $ assignable_permissions         :'data.frame': 3 obs. of  2 variables:
##  $ permissions                    :'data.frame': 3 obs. of  4 variables:
##  $ data                           : chr "https://kobo.correlaid.org/api/v2/assets/avJyi8RUCjQ4RSFA7qdWPG/data/"

Cloning an Asset

In order to clone an asset, you just have to specify its ID, a new name for the cloned asset and its type.

res <- kobo$clone_asset(test_id, "Test survey copy", "survey")
class(res)
## [1] "HttpResponse" "R6"
res$status_http()
## <Status code: 201>
##   Message: Created
##   Explanation: Document created, URL follows

Parse out the ID of the asset that was created:

response_content <- res$parse("UTF-8") %>% jsonlite::fromJSON()
str(response_content, max.level = 1)
## List of 39
##  $ url                            : chr "https://kobo.correlaid.org/api/v2/assets/ackE4RGzXMjWBei3bRHPbb/"
##  $ owner                          : chr "https://kobo.correlaid.org/api/v2/users/api_user/"
##  $ owner__username                : chr "api_user"
##  $ parent                         : NULL
##  $ ancestors                      : NULL
##  $ settings                       :List of 3
##  $ asset_type                     : chr "survey"
##  $ date_created                   : chr "2022-01-24T13:04:49.219153Z"
##  $ summary                        :List of 6
##  $ date_modified                  : chr "2022-01-24T13:04:49.219192Z"
##  $ version_id                     : chr "vfAaB99KXQeGf2gMxWA57z"
##  $ version__content_hash          : chr "f3e28cf31d58b03c955935dedec741d31d4537b8"
##  $ version_count                  : int 1
##  $ has_deployment                 : logi FALSE
##  $ deployed_version_id            : NULL
##  $ deployed_versions              :List of 4
##  $ deployment__identifier         : NULL
##  $ deployment__links              : Named list()
##  $ deployment__active             : logi FALSE
##  $ deployment__data_download_links: Named list()
##  $ deployment__submission_count   : int 0
##  $ report_styles                  :List of 3
##  $ report_custom                  : Named list()
##  $ map_styles                     : Named list()
##  $ map_custom                     : Named list()
##  $ content                        :List of 6
##  $ downloads                      :'data.frame': 2 obs. of  2 variables:
##  $ embeds                         :'data.frame': 2 obs. of  2 variables:
##  $ koboform_link                  : chr "https://kobo.correlaid.org/api/v2/assets/ackE4RGzXMjWBei3bRHPbb/koboform/"
##  $ xform_link                     : chr "https://kobo.correlaid.org/api/v2/assets/ackE4RGzXMjWBei3bRHPbb/xform/"
##  $ hooks_link                     : chr "https://kobo.correlaid.org/api/v2/assets/ackE4RGzXMjWBei3bRHPbb/hooks/"
##  $ tag_string                     : chr ""
##  $ uid                            : chr "ackE4RGzXMjWBei3bRHPbb"
##  $ kind                           : chr "asset"
##  $ xls_link                       : chr "https://kobo.correlaid.org/api/v2/assets/ackE4RGzXMjWBei3bRHPbb/xls/"
##  $ name                           : chr "Test survey copy"
##  $ assignable_permissions         :'data.frame': 9 obs. of  2 variables:
##  $ permissions                    :'data.frame': 8 obs. of  4 variables:
##  $ data                           : chr "https://kobo.correlaid.org/api/v2/assets/ackE4RGzXMjWBei3bRHPbb/data/"
test_clone_id <- response_content$uid

Deploying an asset

To deploy an existing asset, e.g. after cloning or updating:

res <- kobo$deploy_asset(test_clone_id)
class(res)
## [1] "HttpResponse" "R6"
res$status_http()
## <Status code: 200>
##   Message: OK
##   Explanation: Request fulfilled, document follows
response_content <- res$parse("UTF-8") %>% jsonlite::fromJSON()
str(response_content, max.level = 1)
## List of 5
##  $ backend   : chr "kobocat"
##  $ identifier: chr "https://kc.correlaid.org/api_user/forms/ackE4RGzXMjWBei3bRHPbb"
##  $ active    : logi TRUE
##  $ version_id: chr "vfAaB99KXQeGf2gMxWA57z"
##  $ asset     :List of 37

Importing XLS forms

You can import an XLS form. This will create a draft survey/form which you could then again deploy using kobo$deploy_asset().

res <- kobo$import_xls_form(name = "XLS Form via import", "assets/xls_form_downloaded.xls")
res$status_http()
## <Status code: 201>
##   Message: Created
##   Explanation: Document created, URL follows

Making it your own: post and get

kbtbr is by no means complete. So you might find that some of your use cases are not covered by the existing methods of the Kobo class. For this purpose, Kobo as well as the lower-level KoboClient class expose generic get and post functions which should allow you to implement more functionalities on your own. You can check out the existing high-level functions (e.g. get_assets or clone_asset) to get ideas how your code should look like. Of course, contributions to kbtbr are always welcome.