An R package for interacting with the Wildbook v3 API. This package provides an interface for authenticating with Wildbook instances and searching for encounters, individuals, and other data.
- 🔐 Session-based authentication with automatic cookie management
- 🔍 Powerful search capabilities using OpenSearch/Elasticsearch queries
- 🛠️ Helper functions for common query patterns
- 🎯 Simple, intuitive API similar to tidyverse conventions
# Install dependencies first
install.packages(c("httr2", "jsonlite", "R6"))
# Install from local directory
install.packages("path/to/RWildbook", repos = NULL, type = "source")library(RWildbook)library(RWildbook)
# Create a client instance
# The base URL can also be set via the WILDBOOK_URL environment variable
client <- WildbookClient$new(Sys.getenv("WILDBOOK_URL", "http://localhost:8080"))
# Login
# Credentials can be passed directly or sourced from WILDBOOK_USERNAME and WILDBOOK_PASSWORD environment variables
client$login()
# Search for encounters
query <- match_all()
results <- client$search_encounters(query, size = 10)
# Print results
for (encounter in results$hits) {
cat(sprintf("%s: %s %s\n",
encounter$id,
encounter$genus,
encounter$specificEpithet %||% ""))
}
# Logout when done
client$logout()The client uses session-based authentication. After logging in, the session cookie is automatically managed for all subsequent requests. For security, it is highly recommended to use environment variables for sensitive credentials.
# Create client
# The base URL can also be set via the WILDBOOK_URL environment variable
client <- WildbookClient$new(Sys.getenv("WILDBOOK_URL", "http://localhost:8080"))
# Login using environment variables (recommended)
# Credentials sourced from WILDBOOK_USERNAME and WILDBOOK_PASSWORD environment variables
user_info <- client$login()
# Logged in successfully as: user@example.com
# Or login with explicit credentials
user_info <- client$login("user@example.com", "password")
cat(sprintf("User ID: %s\n", user_info$id))
cat(sprintf("Full Name: %s\n", user_info$fullName))
# Check authentication status
if (client$is_authenticated()) {
cat("✓ Authenticated\n")
}
# Get current user info
user <- client$get_current_user()
# Logout
client$logout()# Get all encounters
results <- client$search_encounters(match_all(), size = 50)
# With pagination
results <- client$search_encounters(
match_all(),
from = 0, # offset
size = 20, # page size
sort = "year", # sort field
sort_order = "desc"
)# Get my 10 most recent encounters
my_encounters <- client$search_encounters(
client$filter_current_user(),
size = 10,
sort = "year",
sort_order = "desc"
)
# Combine with other filters: my encounters of a specific species
query <- combine_queries(
client$filter_current_user(),
filter_by_species("Megaptera", "novaeangliae"),
operator = "must"
)
results <- client$search_encounters(query)# Search for humpback whales
query <- filter_by_species("Megaptera", "novaeangliae")
results <- client$search_encounters(query)
# Search by genus only
query <- filter_by_species("Megaptera")
results <- client$search_encounters(query)# Encounters from 2020 to 2023
query <- filter_by_year_range(start_year = 2020, end_year = 2023)
results <- client$search_encounters(query)
# Encounters from 2020 onwards
query <- filter_by_year_range(start_year = 2020)
results <- client$search_encounters(query)# Filter by country
query <- filter_by_location(country = "Kenya")
results <- client$search_encounters(query)
# Filter by bounding box
query <- filter_by_location(
min_lat = -5.0,
max_lat = 5.0,
min_lon = 35.0,
max_lon = 42.0
)
results <- client$search_encounters(query)# Female humpback whales from 2020-2023
species <- filter_by_species("Megaptera", "novaeangliae")
sex <- filter_by_sex("female")
years <- filter_by_year_range(2020, 2023)
query <- combine_queries(species, sex, years, operator = "must")
results <- client$search_encounters(query)# Encounters without an assigned individual
query <- field_missing("individualId")
unassigned <- client$search_encounters(query)# Search for "beach" in locality descriptions
query <- text_search("verbatimLocality", "beach", fuzzy = TRUE)
results <- client$search_encounters(query)# Find individuals with encounters
query <- field_exists("encounters")
results <- client$search_individuals(query, size = 20)
for (individual in results$hits) {
cat(sprintf("%s: %s\n",
individual$id,
individual$displayName %||% "Unnamed"))
}# Get a specific encounter by UUID
encounter <- client$get_encounter("123e4567-e89b-12d3-a456-426614174000")
print(encounter)
# Get a specific individual by UUID
individual <- client$get_individual("987fcdeb-51a2-43f7-9876-543210fedcba")
print(individual)# Get dashboard data for the current user
dashboard <- client$get_user_home()
cat(sprintf("Latest encounters: %d\n", length(dashboard$latestEncounters)))
cat(sprintf("Projects: %d\n", length(dashboard$projects)))The package provides these helper functions for constructing queries:
match_all()- Match all documentsfilter_by_sex(sex)- Filter by sexfilter_by_species(genus, specific_epithet = NULL)- Filter by speciesfilter_by_year_range(start_year, end_year)- Filter by year rangefilter_by_location(country, location_id, min_lat, max_lat, min_lon, max_lon)- Filter by locationfilter_by_individual(individual_id)- Find encounters for an individualfilter_by_submitter(submitter_id)- Filter by submittertext_search(field, text, fuzzy = FALSE)- Text search in a fieldfield_exists(field)- Find documents where field existsfield_missing(field)- Find documents where field is missingcombine_queries(..., operator = "must")- Combine multiple queries with AND/OR/NOT logic
For advanced use cases, you can construct your own OpenSearch/Elasticsearch queries:
# Custom query using Elasticsearch DSL
custom_query <- list(
bool = list(
must = list(
list(term = list(genus = "Tursiops")),
list(range = list(year = list(gte = 2020, lte = 2023)))
),
must_not = list(
list(term = list(sex = "unknown"))
)
)
)
results <- client$search_encounters(custom_query)Results are returned as R lists. You can convert them to data frames for easier analysis:
library(dplyr)
library(purrr)
# Search for encounters
query <- match_all()
results <- client$search_encounters(query, size = 100)
# Convert to data frame
encounters_df <- map_dfr(results$hits, function(hit) {
tibble(
id = hit$id %||% NA,
genus = hit$genus %||% NA,
species = hit$specificEpithet %||% NA,
year = hit$year %||% NA,
sex = hit$sex %||% NA,
locality = hit$verbatimLocality %||% NA,
lat = hit$decimalLatitude %||% NA,
lon = hit$decimalLongitude %||% NA
)
})
# Analyze
encounters_df %>%
group_by(genus, species) %>%
summarise(count = n()) %>%
arrange(desc(count))The client provides clear error messages for different scenarios:
# Handle authentication errors
tryCatch({
client$login("user@example.com", "wrong_password")
}, error = function(e) {
cat("Login failed:", e$message, "\n")
})
# Handle not found errors
tryCatch({
encounter <- client$get_encounter("invalid-uuid")
}, error = function(e) {
cat("Error:", e$message, "\n")
})
# Always logout in finally block
tryCatch({
# ... do work ...
}, finally = {
if (client$is_authenticated()) {
client$logout()
}
})See the examples/ directory for complete examples:
basic_usage.R- Basic login, search, and logoutadvanced_search.R- Complex queries, pagination, and filtering
Run examples:
# Set environment variables
export WILDBOOK_URL="http://localhost:8080"
export WILDBOOK_USERNAME="your@email.com"
export WILDBOOK_PASSWORD="yourpassword"
# Run in R
Rscript examples/basic_usage.R
Rscript examples/advanced_search.RRWildbook/
├── R/
│ ├── client.R # WildbookClient R6 class
│ └── queries.R # Query helper functions
├── man/ # Roxygen2-generated documentation
├── examples/
│ ├── basic_usage.R
│ └── advanced_search.R
├── tests/ # Test files
├── DESCRIPTION # Package metadata
├── NAMESPACE # Package exports
└── README.md
# Install roxygen2
install.packages("roxygen2")
# Generate documentation
roxygen2::roxygenize()# Install testthat
install.packages("testthat")
# Run tests
testthat::test_dir("tests")R6 class for interacting with Wildbook.
$new(base_url)- Create a new client instance$login(username, password)- Authenticate user$logout()- End session$is_authenticated()- Check authentication status$get_current_user()- Get current user info$get_user_home()- Get user dashboard data$search_encounters(query, from = 0, size = 10, sort = NULL, sort_order = NULL)- Search encounters$get_encounter(encounter_id)- Get specific encounter$search_individuals(query, from = 0, size = 10, sort = NULL, sort_order = NULL)- Search individuals$get_individual(individual_id)- Get specific individual
- R >= 4.0.0
- httr2 >= 1.0.0
- jsonlite >= 1.8.0
- R6 >= 2.5.0
For issues and questions:
- GitHub Issues: https://github.com/WildMeOrg/RWildbook/issues
- Wildbook Documentation: https://docs.wildme.org/
- Wildbook - The main Wildbook platform
Built with: