Overview
geefetch provides a unified R interface for
extracting environmental covariates from Google Earth Engine (GEE).
Unlike other GEE R packages, geefetch works without
Python — it uses the GEE REST API directly via
httr2 and gargle.
Key features:
- No Python required — installs like any normal R package
- 19+ built-in datasets — vegetation, climate, soil, topography
-
Single-function extraction —
read_gee()dispatcher + convenience aliases -
Batch extraction —
collect_gee_data()for multi-location, multi-date, multi-dataset - Automatic caching — repeated queries are served from disk
-
User-extensible — register any GEE collection with
gee_register_dataset()
Installation
# From R-Universe (binaries, updated ~1 h after merge to main):
options(repos = c(
"aagi-aus" = "https://aagi-aus.r-universe.dev",
CRAN = "https://cran.r-project.org"
))
install.packages("geefetch")
# Development version (latest commit on main):
pak::pak("AAGI-AUS/geefetch", subdir = "geefetch")Authentication
Read this section fully before running
gee_auth(). Skipping ahead is the fastest way to
spend an afternoon debugging HTTP 403s.
Authentication to Google Earth Engine has two independent concepts
that geefetch exposes together:
| Concept | What it is | Where it lives |
|---|---|---|
| Identity | Which Google account you’re signing in as | OAuth token |
| Resource project | Which Google Cloud project owns your EE calls, quotas, and billing |
project = argument to gee_auth() and
X-Goog-User-Project header |
If the identity is signed into account A but the resource project was created under account B, you’ll get HTTP 403. The rest of this section is about making both match.
Step 1 — Create a Google Cloud project and register it with Earth Engine
You only do this once, before you ever touch R.
Choose one Google account. The rest of this setup — the Cloud project, the EE registration, the OAuth consent — must all happen under the same Google account. Using your institutional account (
*.edu.au,*.gov, etc.) is typical for academic / research work. A personal Gmail account works too. Decide now and stick with it.Create a dedicated Google Cloud project at https://console.cloud.google.com/projectcreate. Give it a memorable name (e.g.
my-geefetch-dev). Google will assign a short Project ID (the string you type, e.g.my-geefetch-dev) and a long Project number (a 12-digit integer, e.g.123456789012). Copy both. You’ll use the project number in R — it’s unambiguous across accounts.Register the project for Earth Engine noncommercial use at https://code.earthengine.google.com/register. Choose Academic or Research, select your new project from the dropdown, fill in the institution details, submit. Academic approval is usually instant.
Enable the Earth Engine API on the project at https://console.cloud.google.com/apis/library/earthengine.googleapis.com — make sure the project picker top-left shows your project, then click Enable.
Verify at https://console.cloud.google.com/apis/dashboard that “Earth Engine API” appears in the enabled APIs list for your project.
Step 2 — Authenticate in R
Use the project number, not the project ID string. This is the single most common cause of the 403 “Earth Engine API has not been used” error — passing the ID can silently resolve to a different project number under a different identity.
library(geefetch)
gee_auth(
project = "123456789012", # <-- YOUR project number as a string
email = "max.moldovan@gmail.com" # <-- the exact Google account
)A browser window will open for Google OAuth (same flow as
googlesheets4). Sign in as the account matching
email, grant consent for Earth Engine and Cloud Platform
scopes, close the tab.
Step 3 — Verify
## -- geefetch status --
## v Authenticated: yes
## i Project: "123456789012"
## i Backend: REST API (httr2 + gargle)
## i Cache dir: '~/Library/Caches/.../geefetch'
## i Registered datasets: 19
The Project: line must show your project
number. If it shows an ID string like
"earthengine-legacy" or a different number, stop and re-run
gee_auth() with the correct arguments.
Step 4 — Persist across sessions
Add to your .Rprofile (or the top of each analysis
script) so you don’t need to re-type the project number:
options(geefetch.project = "123456789012")
# Then gee_auth() picks it up without explicit project arg.Non-interactive authentication
For CI, HPC, or any unattended context, use a service-account key file. Create the key on the same Cloud project used above (https://console.cloud.google.com/iam-admin/serviceaccounts), grant it the Earth Engine Resource Writer role, download the JSON, then:
gee_auth(
project = "123456789012",
path = "path/to/service-account.json"
)Store the key file outside your repository. Never commit it.
Troubleshooting — HTTP 403 decision tree
If read_modis_ndvi() or any read_*() call
returns a 403 after authentication appeared to succeed, the error
message contains a project number. Match that number against what you
expect:
| Error’s project number | Meaning | Fix |
|---|---|---|
Matches your project =
|
Earth Engine API not actually enabled, or registration not yet propagated | Re-verify Step 1 items 3 + 4; wait 2-3 minutes and retry |
| Different number | OAuth token’s quota project disagrees with your resource project | Restart R; wipe gargle’s token cache
(unlink(list.files(gargle::gargle_oauth_cache(), full.names = TRUE)));
re-run gee_auth() with the project number,
not the ID |
If neither helps, gee_setup() prints the full check-list
and links to the three Google Cloud Console pages involved.
Your first extraction
Extract MODIS NDVI for a region in South Australia:
library(terra)
# Define a region of interest
aoi <- ext(138, 140, -36, -34)
# Extract NDVI for a specific date
ndvi <- read_modis_ndvi(date = "2024-06-15", region = aoi)
# Plot the result
plot(ndvi, main = "MODIS NDVI — 15 June 2024")The result is a standard terra::SpatRaster — you can use
all terra functions for analysis, cropping, masking, and
export.
Point extraction
To extract values at specific coordinates, use
terra::extract():
# Define some sites
sites <- data.frame(
lon = c(138.6, 139.5, 140.2),
lat = c(-34.9, -35.5, -34.2)
)
# Convert to spatial points
pts <- vect(sites, geom = c("lon", "lat"), crs = "EPSG:4326")
# Extract NDVI at the sites
values <- extract(ndvi, pts)
print(values)## ID NDVI
## 1 1 0.3245
## 2 2 0.4512
## 3 3 0.2891
Using the dispatcher
All convenience functions (read_modis_ndvi(),
read_era5(), etc.) are thin wrappers around the central
read_gee() dispatcher. You can use either form:
# These are equivalent:
ndvi <- read_modis_ndvi(date = "2024-06-15", region = aoi)
ndvi <- read_gee("MODIS_NDVI", date = "2024-06-15", region = aoi)
ndvi <- read_gee("NDVI", date = "2024-06-15", region = aoi) # aliasBrowsing available datasets
## dataset collection domain resolution temporal
## 1: modis_ndvi MODIS/061/MOD13A2 Vegetation 1000m 16day
## 2: modis_lst MODIS/061/MOD11A2 Temperature 1000m 8day
## 3: era5_temp ECMWF/ERA5_LAND/DAILY_AGGR Climate 11132m daily
## ...
## 19: openlandmap_ph OpenLandMap/SOL/SOL_PH-H2O_... Soil (Global) 250m static
Caching
geefetch automatically caches extraction results to disk. Repeated identical queries are served instantly:
# First call: hits GEE REST API (~2-5 seconds)
elev <- read_srtm(region = aoi)
# Second call: served from disk cache (< 10 ms)
elev <- read_srtm(region = aoi)
# Check cache size
gee_status()
# Clear cache if needed
gee_clear_cache()Next steps
- See
vignette("collect_gee_data")for batch extraction across multiple locations, dates, and datasets - See
vignette("custom_datasets")for registering your own GEE collections - See
gee_datasets()for the full list of supported datasets