Skip to contents

Introduction

meetupr is an R package that provides a client for the Meetup.com GraphQL API. It allows you to search for groups, retrieve event information, get member lists, and access other Meetup data directly from R. This vignette will guide you through setup, authentication, and common use cases.

Quick Setup Check

Start by running meetup_sitrep() to check your authentication status or set up authentication:

meetup_sitrep()
#> 
#> ── meetupr Situation Report ────────────────────────────────────────────────────
#> 
#> ── Active Authentication Method ──
#> 
#>  OAuth (CI Mode) - "Active"
#>  Cached Token: None - run `get_self()`
#>  CI environment detected
#> 
#> ── Package Settings ──
#> 
#>  Debug Mode: Disabled
#>  API endpoint: <https://api.meetup.com/gql-ext>
#> 
#> ── API Connectivity Test ──
#> 
#>  API Connection: Working
#>  Authenticated as: R-Ladies Global (ID: 251470805)

This function shows you:

  • Which authentication method is currently active
  • Whether your credentials are properly configured
  • API connectivity status
  • Setup instructions if authentication is missing

The function provides actionable feedback, telling you exactly what to do if authentication isn’t working.

Authentication

Authentication is required to access the Meetup API. meetupr supports two authentication methods: interactive OAuth (for local development) and CI/CD authentication (for automated workflows).

Interactive Authentication

For interactive use (exploring data, one-off analyses), simply authenticate when prompted:

# Authenticate interactively (opens browser)
meetup_auth()

# Check authentication status
meetup_auth_status()

When you run meetup_auth():

  1. A browser window opens to Meetup’s authorization page
  2. You log in with your Meetup credentials
  3. You grant permission to the meetupr app
  4. The OAuth token is securely cached on your system

The OAuth token is stored locally in your httr2 cache directory. Token files follow the naming pattern: {hash}-token.rds.enc. These files are encrypted and specific to your system.

You only need to authenticate once. The token will be reused in future R sessions until it expires (typically after 90 days).

CI/CD Authentication

For automated workflows (GitHub Actions, scheduled scripts, etc.), you need token-based authentication that doesn’t require browser interaction.

Step 1: Set up CI credentials locally

# First authenticate interactively
meetup_auth()

# Then set up CI credentials
meetup_ci_setup()

The meetup_ci_setup() function will:

  1. Encode your existing OAuth token as base64
  2. Store the encoded token in your system keyring
  3. Display the token and filename for setting CI secrets
  4. Provide instructions for your CI platform

Step 2: Set environment variables in your CI

In your CI platform (GitHub Actions, GitLab CI, etc.), set these secrets:

  • meetupr:token: Base64-encoded token (from step 1)
  • meetupr:token_file: Token filename (e.g., ae743e0-token.rds.enc)

For GitHub Actions, your workflow YAML should include:

env:
  "meetupr:token": ${{ secrets.MEETUPR_TOKEN }}
  "meetupr:token_file": ${{ secrets.MEETUPR_TOKEN_FILE }}

Important: Quote the environment variable names in YAML because they contain colons.

Step 3: Load token in CI

Add this line at the beginning of your CI script, before any API calls:

This function decodes the base64 token and writes it to the expected cache location. All subsequent API calls will use this token automatically.

Deauthentication

To remove cached credentials:

# Clear authentication completely
meetup_deauth()

The meetup_deauth() function removes all cached tokens and clears authentication state. You’ll need to re-authenticate the next time you make an API call.

Verification

After authenticating, verify the setup:

meetup_sitrep()
#> 
#> ── meetupr Situation Report ────────────────────────────────────────────────────
#> 
#> ── Active Authentication Method ──
#> 
#>  OAuth (CI Mode) - "Active"
#>  Cached Token: None - run `get_self()`
#>  CI environment detected
#> 
#> ── Package Settings ──
#> 
#>  Debug Mode: Disabled
#>  API endpoint: <https://api.meetup.com/gql-ext>
#> 
#> ── API Connectivity Test ──
#> 
#>  API Connection: Working
#>  Authenticated as: R-Ladies Global (ID: 251470805)

The output shows:

  • Whether an OAuth token exists and is valid
  • Whether you’re in CI mode (token loaded from environment variables)
  • API connectivity status

Basic Usage Examples

Once authenticated, you can start querying the Meetup API. All functions return tibbles (data frames) for easy manipulation with dplyr and other tidyverse packages.

Get Group Information

Retrieve detailed information about a specific group using its URL name (the part after meetup.com/ in the URL):

group_info <- get_group("rladies-lagos")
str(group_info)
#> List of 13
#>  $ id          : chr "32612004"
#>  $ name        : chr "R-Ladies Lagos"
#>  $ description : chr "R-Ladies is a world-wide organization to promote gender diversity in the R community.\nR-Ladies welcomes member"| __truncated__
#>  $ urlname     : chr "rladies-lagos"
#>  $ link        : chr "https://www.meetup.com/rladies-lagos"
#>  $ location    :List of 2
#>   ..$ city   : chr "Lagos"
#>   ..$ country: chr "ng"
#>  $ timezone    : chr "Africa/Lagos"
#>  $ created     : POSIXct[1:1], format: "2019-08-16 08:45:21"
#>  $ members     : int 880
#>  $ total_events: int 13
#>  $ organizer   :List of 2
#>   ..$ id  : chr "251470805"
#>   ..$ name: chr "R-Ladies Global"
#>  $ category    :List of 2
#>   ..$ id  : chr "546"
#>   ..$ name: chr "Technology"
#>  $ photo_url   : chr "https://secure-content.meetupstatic.com/images/classic-events/"
#>  - attr(*, "class")= chr [1:2] "meetup_group" "list"

The result includes:

  • Group name, description, and URL
  • Location (city, state, country)
  • Member count
  • Organizer information
  • Group creation date

List Group Events

Get events for a specific group. By default, this returns upcoming events:

events <- get_group_events("rladies-lagos")
head(events)
#> # A tibble: 6 × 23
#>   id     title event_url created_time        status date_time           duration
#>   <chr>  <chr> <chr>     <dttm>              <chr>  <dttm>              <chr>   
#> 1 26415… satR… https://… 2019-08-20 11:54:50 PAST   2019-09-21 08:00:00 PT7H    
#> 2 26675… Data… https://… 2019-11-26 17:00:29 PAST   2019-12-07 08:00:00 PT7H    
#> 3 26780… Gett… https://… 2020-01-10 12:56:39 PAST   2020-02-22 08:00:00 PT7H    
#> 4 28432… Data… https://… 2022-03-01 00:27:32 PAST   2022-03-26 13:00:00 PT2H    
#> 5 28461… R La… https://… 2022-03-14 16:37:46 PAST   2022-05-07 15:00:00 PT1H    
#> 6 29226… Wome… https://… 2023-03-15 19:29:08 PAST   2023-03-24 09:00:00 PT2H    
#> # ℹ 16 more variables: description <chr>, group_id <chr>, group_name <chr>,
#> #   group_urlname <chr>, venues_id <list>, venues_name <list>,
#> #   venues_address <list>, venues_city <list>, venues_state <list>,
#> #   venues_postal_code <list>, venues_country <list>, venues_lat <list>,
#> #   venues_lon <list>, venues_venue_type <list>, rsvps_count <int>,
#> #   featured_event_photo_url <chr>

Each row represents an event with:

  • Event ID, title, and description
  • Date and time (as POSIXct objects)
  • Duration
  • RSVP counts (yes, waitlist, total)
  • Venue information (if available)

Get Past Events

To retrieve historical events, use the status parameter:

past_events <- get_group_events(
  "rladies-lagos",
  status = "past",
  max_results = 10
)
head(past_events)
#> # A tibble: 6 × 23
#>   id     title event_url created_time        status date_time           duration
#>   <chr>  <chr> <chr>     <dttm>              <chr>  <dttm>              <chr>   
#> 1 26415… satR… https://… 2019-08-20 11:54:50 PAST   2019-09-21 08:00:00 PT7H    
#> 2 26675… Data… https://… 2019-11-26 17:00:29 PAST   2019-12-07 08:00:00 PT7H    
#> 3 26780… Gett… https://… 2020-01-10 12:56:39 PAST   2020-02-22 08:00:00 PT7H    
#> 4 28432… Data… https://… 2022-03-01 00:27:32 PAST   2022-03-26 13:00:00 PT2H    
#> 5 28461… R La… https://… 2022-03-14 16:37:46 PAST   2022-05-07 15:00:00 PT1H    
#> 6 29226… Wome… https://… 2023-03-15 19:29:08 PAST   2023-03-24 09:00:00 PT2H    
#> # ℹ 16 more variables: description <chr>, group_id <chr>, group_name <chr>,
#> #   group_urlname <chr>, venues_id <chr>, venues_name <chr>,
#> #   venues_address <chr>, venues_city <chr>, venues_state <chr>,
#> #   venues_postal_code <chr>, venues_country <chr>, venues_lat <dbl>,
#> #   venues_lon <dbl>, venues_venue_type <chr>, rsvps_count <int>,
#> #   featured_event_photo_url <chr>

Valid status values are:

  • upcoming: Future events (default)
  • past: Historical events
  • cancelled: Cancelled events
  • draft: Draft events (if you’re a group organizer)

Filter Events by Date

You can filter events within a specific date range:

# Events from 2024 onwards
recent_events <- get_group_events(
  "rladies-lagos",
  status = "past",
  date_after = "2024-01-01T00:00:00Z"
)
head(recent_events)
#> # A tibble: 3 × 23
#>   id     title event_url created_time        status date_time           duration
#>   <chr>  <chr> <chr>     <dttm>              <chr>  <dttm>              <chr>   
#> 1 30002… Buil… https://… 2024-03-26 12:37:08 PAST   2024-04-06 16:00:00 PT3H    
#> 2 30035… Inte… https://… 2024-04-11 19:14:08 PAST   2024-04-25 10:00:00 PT5H    
#> 3 30002… Inte… https://… 2024-03-26 13:08:58 PAST   2024-04-27 16:00:00 PT3H    
#> # ℹ 16 more variables: description <chr>, group_id <chr>, group_name <chr>,
#> #   group_urlname <chr>, venues_id <list>, venues_name <list>,
#> #   venues_address <list>, venues_city <list>, venues_state <list>,
#> #   venues_postal_code <list>, venues_country <list>, venues_lat <list>,
#> #   venues_lon <list>, venues_venue_type <list>, rsvps_count <int>,
#> #   featured_event_photo_url <chr>

Dates must be in ISO 8601 format with timezone (typically UTC: YYYY-MM-DDTHH:MM:SSZ).

Get Event Details

Retrieve detailed information about a specific event using its ID:

event <- get_event(id = "103349942")
event
#> 
#> ── Meetup Event ──
#> 
#> • ID: "103349942"
#> • Title: Ecosystem GIS & Community Building
#> • Status: "PAST"
#> • Date/Time: 2013-02-18T18:30:00-05:00
#> • Duration: PT2H
#> • RSVPs: 97
#> 
#> ── Group:
#> • Data Visualization DC ("data-visualization-dc")
#> 
#> ── Venue:
#> • Name: Browsermedia/NClud
#> • Location: Washington, DC, us
#> 
#> <https://www.meetup.com/data-visualization-dc/events/103349942/>

The print() method displays a formatted summary. Access individual fields with $ notation:

event$title
event$dateTime
event$going

Get Event RSVPs

See who has RSVP’d to an event:

rsvps <- get_event_rsvps(id = "103349942")
head(rsvps)
#> # A tibble: 6 × 9
#>   id        member_id member_name         member_bio member_url member_photo_url
#>   <chr>     <chr>     <chr>               <chr>      <chr>      <chr>           
#> 1 683104152 12251810  Sean Moore Gonzalez "Backgrou… https://w… https://secure-…
#> 2 683108312 482161    Harlan Harris       ""         https://w… https://secure-…
#> 3 683109202 6382386   Harnam Rai          ""         https://w… https://secure-…
#> 4 683114012 70383262  Dario Rivera        ""         https://w… https://secure-…
#> 5 683114892 8783792   Aaron M             ""         https://w… https://secure-…
#> 6 683118132 10948775  Sam                 ""         https://w… https://secure-…
#> # ℹ 3 more variables: member_organized_group_count <int>, guests_count <int>,
#> #   status <chr>

Each row represents one RSVP with:

  • Member ID and name
  • RSVP response (yes, no, waitlist)
  • Number of guests
  • RSVP creation time

This is useful for analyzing attendance patterns or contacting attendees (with appropriate permissions).

Get Group Members

List members of a group:

members <- get_group_members("rladies-lagos", max_results = 10)
head(members)
#> # A tibble: 6 × 4
#>   id        name                 member_url                     member_photo_url
#>   <chr>     <chr>                <chr>                          <chr>           
#> 1 251470805 R-Ladies Global      https://www.meetup.com/member… https://secure-…
#> 2 225839690 EYITAYO ALIMI        https://www.meetup.com/member… https://secure-…
#> 3 236466773 Adedamilola Adekanye https://www.meetup.com/member… https://secure-…
#> 4 255806325 Helen                https://www.meetup.com/member… https://secure-…
#> 5 287781170 Alvin                https://www.meetup.com/member… https://secure-…
#> 6 266271010 ijeoma benson        https://www.meetup.com/member… NA

Member data includes:

  • Member ID and name
  • Join date
  • Member status (active, organizer, etc.)
  • Bio and profile URL

Note: Due to privacy settings, some member information may be limited.

Search for Groups

Find groups matching a search term:

r_groups <- find_groups("R programming")
head(r_groups)
#> # A tibble: 6 × 14
#>   id       name      urlname city  state country   lat     lon memberships_count
#>   <chr>    <chr>     <chr>   <chr> <chr> <chr>   <dbl>   <dbl>             <int>
#> 1 38207702 Birmingh… bham-r… Birm… "AL"  us       33.5  -86.8                  5
#> 2 24890872 Warwick … warwic… Cove… "43"  gb       52.4   -1.56               919
#> 3 18574545 Johannes… joburg… Joha… ""    za      -26.2   28.0               1557
#> 4 2906882  Birmingh… Birmin… Birm… "43"  gb       52.5   -1.9                808
#> 5 23174619 R-Ladies… rladie… Sant… ""    ar      -36.6  -64.3                185
#> 6 26517118 Salt Lak… slc-rug Salt… "UT"  us       40.8 -112.                3050
#> # ℹ 5 more variables: founded_date <dttm>, timezone <chr>, join_mode <chr>,
#> #   is_private <lgl>, membership_status <chr>

Search results include:

  • Group name and URL name
  • Location
  • Member count
  • Description snippet

This is useful for discovering groups in your area or analyzing group networks.

Pagination and Rate Limits

The Meetup API limits how many results can be returned in a single request. The max_results parameter controls pagination:

# Get up to 50 events (may require multiple API calls)
many_events <- get_group_events(
  "rladies-san-francisco",
  status = "past",
  max_results = 50
)

cli::cli_alert_info("Retrieved {nrow(many_events)} events")
#>  Retrieved 50 events

meetupr automatically handles pagination behind the scenes. It makes multiple API requests if needed and combines the results into a single tibble.

The Meetup API rate limit is 500 requests per 60 seconds. meetupr automatically throttles requests to stay under this limit. For large batch operations, consider adding explicit delays:

# Process multiple groups with delays
groups <- c("rladies-nyc", "rladies-sf", "rladies-london")

events <- purrr::map_dfr(groups, \(x) {
  result <- get_group_events(x, max_results = 20)
  Sys.sleep(0.5)  # 500ms delay between requests
  result
})

Pro Account Features

If you have a Meetup Pro account, you can access network-wide data using the Pro functions. These functions require appropriate permissions and will error if you don’t have Pro access.

List All Pro Groups

# Get all groups in the R-Ladies network
pro_groups <- get_pro_groups("rladies")
head(pro_groups)

Network-Wide Events

# Get upcoming events across all groups in network
upcoming <- get_pro_events("rladies", status = "upcoming")
head(upcoming)

# Get cancelled events
cancelled <- get_pro_events("rladies", status = "cancelled")
head(cancelled)

Pro functions return data for all groups in your network with a single API call, which is more efficient than querying each group individually.

Debug Mode

Sometimes issues arise due to misconfiguration or unexpected API behavior. Enabling debug mode shows the exact GraphQL queries being sent to the API.

Enable debugging by setting the MEETUPR_DEBUG environment variable to 1:

local_meetupr_debug(1)
meetup_sitrep()
#> 
#> ── meetupr Situation Report ────────────────────────────────────────────────────
#> 
#> ── Active Authentication Method ──
#> 
#>  OAuth (CI Mode) - "Active"
#>  Cached Token: None - run `get_self()`
#>  CI environment detected
#> 
#> ── Package Settings ──
#> 
#>  Debug Mode: Enabled
#>  API endpoint: <https://api.meetup.com/gql-ext>
#> 
#> ── API Connectivity Test ──
#> 
#>  DEBUG: JSON to be sent:
#> {
#>   "query": "query GetSelf{
#>   self {
#>     id
#>     name
#>     email
#>     isOrganizer
#>     isLeader
#>     isMemberPlusSubscriber  
#>     isProOrganizer
#>     adminProNetworks  {
#>       id
#>       name
#>     }
#>     bio 
#>     city 
#>     country 
#>     state 
#>     lat 
#>     lon 
#>     startDate 
#>     preferredLocale 
#>     memberUrl 
#>     
#>   }
#> }",
#>   "variables": {}
#> }
#>  API Connection: Working
#>  Authenticated as: R-Ladies Global (ID: 251470805)
find_groups("R programming")
#>  DEBUG: JSON to be sent:
#> {
#>   "query": "query findGroups(
#>   $query: String!
#>   $cursor: String
#>   $first: Int = 1000
#>   $lat: Float = 0.0
#>   $lon: Float = 0.0
#>   $radius: Float = 100000000.0
#>   $categoryId: ID
#>   $topicCategoryId: ID
#> ) {
#>   groupSearch(
#>     after: $cursor
#>     first: $first
#>     filter: {
#>       query: $query
#>       lat: $lat
#>       lon: $lon
#>       radius: $radius
#>       categoryId: $categoryId
#>       topicCategoryId: $topicCategoryId
#>     }
#>   ) {
#>     pageInfo {
#>       hasNextPage
#>       endCursor
#>     }
#>     totalCount
#>     edges {
#>       node {
#>         id
#>         name
#>         urlname
#>         city
#>         state
#>         country
#>         lat
#>         lon
#>         memberships {
#>           totalCount
#>         }
#>         foundedDate
#>         timezone
#>         joinMode
#>         isPrivate
#>         membershipMetadata {
#>           status
#>         }
#>       }
#>     }
#>     
#>   }
#> }",
#>   "variables": {
#>     "query": "R programming",
#>     "first": 200
#>   }
#> }
#> # A tibble: 200 × 14
#>    id       name     urlname city  state country   lat     lon memberships_count
#>    <chr>    <chr>    <chr>   <chr> <chr> <chr>   <dbl>   <dbl>             <int>
#>  1 38207702 Birming… bham-r… Birm… "AL"  us       33.5  -86.8                  5
#>  2 24890872 Warwick… warwic… Cove… "43"  gb       52.4   -1.56               919
#>  3 18574545 Johanne… joburg… Joha… ""    za      -26.2   28.0               1557
#>  4 2906882  Birming… Birmin… Birm… "43"  gb       52.5   -1.9                808
#>  5 23174619 R-Ladie… rladie… Sant… ""    ar      -36.6  -64.3                185
#>  6 26517118 Salt La… slc-rug Salt… "UT"  us       40.8 -112.                3050
#>  7 20443056 R-Ladie… rladie… Paris ""    fr       48.9    2.34              1143
#>  8 21760043 R-Ladie… rladie… Buen… ""    ar      -34.6  -58.4               1966
#>  9 37281989 Cape To… cape-t… Cape… ""    za      -33.9   18.5                110
#> 10 17428672 R Users… spotka… Wars… ""    pl       52.3   21.0               2975
#> # ℹ 190 more rows
#> # ℹ 5 more variables: founded_date <dttm>, timezone <chr>, join_mode <chr>,
#> #   is_private <lgl>, membership_status <chr>

Debug output includes:

  • The complete GraphQL query sent to the API
  • Variable values being passed
  • The raw JSON response

This is invaluable when queries fail unexpectedly or you’re unsure what data is being returned.

To turn it off again, set it to 0:

local_meetupr_debug(0)
meetup_sitrep()
#> 
#> ── meetupr Situation Report ────────────────────────────────────────────────────
#> 
#> ── Active Authentication Method ──
#> 
#>  OAuth (CI Mode) - "Active"
#>  Cached Token: None - run `get_self()`
#>  CI environment detected
#> 
#> ── Package Settings ──
#> 
#>  Debug Mode: Disabled
#>  API endpoint: <https://api.meetup.com/gql-ext>
#> 
#> ── API Connectivity Test ──
#> 
#>  API Connection: Working
#>  Authenticated as: R-Ladies Global (ID: 251470805)
find_groups("R programming")
#> # A tibble: 200 × 14
#>    id       name     urlname city  state country   lat     lon memberships_count
#>    <chr>    <chr>    <chr>   <chr> <chr> <chr>   <dbl>   <dbl>             <int>
#>  1 38207702 Birming… bham-r… Birm… "AL"  us       33.5  -86.8                  5
#>  2 24890872 Warwick… warwic… Cove… "43"  gb       52.4   -1.56               919
#>  3 18574545 Johanne… joburg… Joha… ""    za      -26.2   28.0               1557
#>  4 2906882  Birming… Birmin… Birm… "43"  gb       52.5   -1.9                808
#>  5 23174619 R-Ladie… rladie… Sant… ""    ar      -36.6  -64.3                185
#>  6 26517118 Salt La… slc-rug Salt… "UT"  us       40.8 -112.                3050
#>  7 20443056 R-Ladie… rladie… Paris ""    fr       48.9    2.34              1143
#>  8 21760043 R-Ladie… rladie… Buen… ""    ar      -34.6  -58.4               1966
#>  9 37281989 Cape To… cape-t… Cape… ""    za      -33.9   18.5                110
#> 10 17428672 R Users… spotka… Wars… ""    pl       52.3   21.0               2975
#> # ℹ 190 more rows
#> # ℹ 5 more variables: founded_date <dttm>, timezone <chr>, join_mode <chr>,
#> #   is_private <lgl>, membership_status <chr>

For persistent debugging across R sessions, set the environment variable in your .Renviron file:

MEETUPR_DEBUG=1

Common Issues

Authentication Errors

Error: Authentication required

Solution: Run meetup_sitrep() to diagnose the issue. Common causes include:

  • No OAuth token cached (run meetup_auth())
  • Expired token (re-authenticate with meetup_auth())
  • Missing CI environment variables (check meetupr:token and meetupr:token_file)

Multiple Token Warning

Warning: Multiple tokens found in cache

Solution: Clear old tokens and re-authenticate:

This happens when tokens from different OAuth applications accumulate in your cache directory.

Rate Limiting

Error: Rate limit exceeded

Solution: The Meetup API limits you to 500 requests per 60 seconds. If you hit this limit:

  1. Add delays between requests (Sys.sleep(0.5))
  2. Reduce max_results to minimize pagination
  3. Cache results locally to avoid repeated queries

meetupr automatically throttles requests, but aggressive batch operations may still hit limits.

Group Not Found

Error: Group not found

Solution: Verify the group URL name. The URL name is the part after meetup.com/ in the group’s URL. For example, for https://www.meetup.com/rladies-san-francisco/, the URL name is rladies-san-francisco.

CI Token Expired

If CI authentication fails with “token expired”:

# Locally, refresh token
meetup_auth()
meetup_ci_setup()

# Update CI secrets with new values shown by meetup_ci_setup()

You’ll need to refresh CI secrets periodically.

Next Steps

Now that you’re set up, explore more advanced features:

  • Custom GraphQL Queries: See the GraphQL vignette to write custom queries and access fields not available through wrapper functions
  • Custom OAuth Application: See the Advanced Authentication vignette for setting up your own OAuth app for higher rate limits
  • API Schema Exploration: See the Inspecting the API vignette for exploring the Meetup GraphQL schema
  • Data Analysis: Combine meetupr with dplyr, ggplot2, and other tidyverse packages for analysis and visualization

For package updates and issues, visit the GitHub repository.

Getting Help

If you encounter issues:

  1. Check meetup_sitrep() for authentication diagnostics
  2. Enable debug mode (local_meetupr_debug(1)) to see API queries
  3. Search existing issues on GitHub
  4. File a bug report with a reproducible example (use reprex::reprex())

When reporting issues, include:

This helps maintainers diagnose and fix problems quickly.