# How to Integrate Retool with GoToWebinar

- Tool: Retool
- Difficulty: Intermediate
- Time required: 25 minutes
- Last updated: April 2026

## TL;DR

Connect Retool to GoToWebinar using a REST API Resource authenticated with GoTo's OAuth 2.0. Once configured, query GoToWebinar's REST API to list upcoming and past webinars, manage registrants, track attendance, and export attendee lists. GoTo's unified OAuth grants access to both GoToWebinar and GoToMeeting endpoints from a single Resource configuration, making it easy to build a comprehensive webinar operations dashboard in Retool.

## Why connect Retool to GoToWebinar?

Webinar marketing and events teams run GoToWebinar campaigns that generate valuable registrant data — but GoToWebinar's native reporting is limited to basic attendance exports and its integration options require paid Zapier connections or manual CSV downloads. Retool provides direct API access to all webinar data: registrant lists, session performance, attendee duration, and poll responses. This enables internal operational tools that teams actually want to use: a post-webinar follow-up panel that shows who attended, for how long, and immediately triggers personalized CRM updates based on attendance data.

The most impactful Retool-GoToWebinar integrations combine attendance data with CRM records. A marketing ops dashboard can pull the GoToWebinar attendee list and join it with Salesforce or HubSpot contact records to immediately see which leads attended, score them based on attendance duration (watched more than 50% = high intent), and trigger follow-up sequences — all within a single Retool app that eliminates the CSV export and manual CRM update workflow that teams currently do after every webinar.

GoToWebinar's API is comprehensive for event management. You can create webinars, add and update registrants programmatically, retrieve session recordings, access poll and survey responses, and pull engagement metrics per attendee session. Combined with Retool's ability to trigger actions in other systems, the integration enables a fully automated post-webinar operations workflow without custom backend code.

## Before you start

- A GoToWebinar account with organizer-level access and an active subscription
- A registered GoTo developer app with webinar OAuth scopes (create at developer.goto.com)
- The GoToWebinar organizer key from your account settings
- A Retool account with Resource creation permissions
- Optional: access to a CRM (HubSpot, Salesforce) Resource in Retool for cross-source follow-up workflows

## Step-by-step guide

### 1. Register a GoTo developer app with webinar scopes

Navigate to GoTo Developer Center at developer.goto.com and sign in with your GoToWebinar organizer account. Click My Apps and then Create an App. Name the app Retool Webinar Manager and select OAuth as the authentication method. In the Products section, enable GoToWebinar and optionally GoToMeeting if you want to access both from the same Resource. In Redirect URIs, add the Retool OAuth callback URL: https://oauth.retool.com/oauth/user/oauthcallback for Retool Cloud. Select the required OAuth scopes for webinar access: collab:webinars:read to list webinars and retrieve registrant and attendee data, and collab:webinars:write to create webinars and manage registrants. Save the app and copy the Client ID and Client Secret that GoTo generates. You will also need your GoToWebinar organizer key — find this by logging into app.goto.com, clicking your profile, and going to My Account. The organizer key is a numeric value that identifies your GoToWebinar account and is required in all API endpoint paths. Store the organizer key alongside your OAuth credentials as you will configure it in a Retool configuration variable in the next step.

**Expected result:** A GoTo developer app is registered at developer.goto.com with the Retool OAuth callback URL and webinar scopes configured. You have the Client ID, Client Secret, and your GoToWebinar organizer key ready.

### 2. Create the GoToWebinar REST API Resource and configure the organizer key

Navigate to the Resources tab in Retool and click Add Resource → REST API. Name the resource GoToWebinar API. Set the Base URL to https://api.getgo.com. In the Authentication section, select OAuth 2.0. Fill in the fields: Authorization URL as https://authentication.logmeininc.com/oauth/authorize, Token URL as https://authentication.logmeininc.com/oauth/token, your Client ID and Client Secret from the developer portal, and the Scope as collab:webinars:read collab:webinars:write (space-separated). Add access_type: offline to the additional OAuth parameters for refresh token support. Save and click Connect to trigger the GoTo OAuth flow in a popup. Sign in with your GoToWebinar organizer account and authorize the requested scopes. After authorization, the resource shows as Connected. Next, navigate to Settings → Configuration Variables and add a new variable named GOTO_ORGANIZER_KEY with the numeric organizer key value from your GoToWebinar account. Mark it as a secret to prevent it from appearing in frontend query logs. All GoToWebinar API endpoints require this key as a URL path segment: the path pattern is /G2W/rest/v2/organizers/{organizerKey}/webinars. Reference it in queries as {{ retoolContext.configVars.GOTO_ORGANIZER_KEY }}.

**Expected result:** The GoToWebinar REST API Resource is Connected in Retool with OAuth authentication established, and the organizer key is securely stored in a configuration variable for use in API endpoint paths.

### 3. List upcoming webinars and build the webinar selector

Create a new query named getUpcomingWebinars. Select the GoToWebinar API resource. Set the HTTP method to GET and the path to /G2W/rest/v2/organizers/{{ retoolContext.configVars.GOTO_ORGANIZER_KEY }}/webinars. Add query parameters: fromTime set to {{ new Date().toISOString() }} (current time in ISO 8601 UTC format) and toTime set to {{ new Date(Date.now() + 90*24*60*60*1000).toISOString() }} (90 days ahead). The GoToWebinar API returns a _embedded.webinars array (note the HAL+JSON hypermedia format) with each webinar object containing: webinarKey, subject, description, organizerKey, timeZone, registrationUrl, and a times array with start and end times for single-session or multi-session webinars. Create a JavaScript transformer to flatten the nested structure into a clean array. Drag a Select component onto the canvas labeled Select Webinar and bind its data to the transformed webinar list, using the webinar subject as the label and webinarKey as the value. Drag a Table component below and bind it to {{ getUpcomingWebinars.data }} to display all upcoming webinars with their details. Add Stat components showing total upcoming webinars, total sessions this quarter, and average registrations per webinar (calculated from a separate registrations query).

```
// Transformer: flatten GoToWebinar _embedded.webinars response
const webinars = (data._embedded && data._embedded.webinars) || data.webinars || [];

return webinars.map(w => {
  const firstSession = (w.times && w.times[0]) || {};
  const startTime = firstSession.startTime ? new Date(firstSession.startTime) : null;
  const endTime = firstSession.endTime ? new Date(firstSession.endTime) : null;
  const durationMin = startTime && endTime
    ? Math.round((endTime - startTime) / 60000)
    : null;
  
  return {
    webinar_key: w.webinarKey,
    subject: w.subject || '(No subject)',
    description: (w.description || '').substring(0, 100) + (w.description?.length > 100 ? '...' : ''),
    start_date: startTime ? startTime.toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' }) : 'TBD',
    start_time: startTime ? startTime.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }) : '',
    duration_min: durationMin,
    timezone: w.timeZone || '',
    session_count: (w.times || []).length,
    registration_url: w.registrationUrl || ''
  };
}).sort((a, b) => new Date(a.start_date) - new Date(b.start_date));
```

**Expected result:** A Select dropdown lists all upcoming GoToWebinar events and a Table below shows their details including subject, date, time, duration, and registration URL.

### 4. Retrieve registrants and attendance for a selected webinar

Create a query named getRegistrants. Set the HTTP method to GET and path to /G2W/rest/v2/organizers/{{ retoolContext.configVars.GOTO_ORGANIZER_KEY }}/webinars/{{ webinarSelector.value }}/registrants where webinarSelector is the Select component from the previous step. The registrants endpoint returns a _embedded.registrants array with each registrant's registrantKey, firstName, lastName, email, registrationDate, status, and any custom question responses in the responses array. Create a second query named getAttendees for past webinars: set the path to /G2W/rest/v2/organizers/{{ retoolContext.configVars.GOTO_ORGANIZER_KEY }}/webinars/{{ webinarSelector.value }}/attendees. Attendee records include the registrantKey, sessionKey, attendanceTimeInSeconds, joinTime, leaveTime, and inSession fields. Use a JavaScript query to join registrant and attendee data on registrantKey to produce a combined list showing each registrant, whether they attended, their attendance duration, and their registration answers. Drag a Table and bind it to this joined dataset. Add column groups: Registration Info (name, email, registration date) and Attendance Info (attended yes/no, duration minutes, join time). Add conditional formatting to highlight attended rows in green and no-show rows in yellow.

```
// JavaScript query: join registrant and attendee data
const registrants = getRegistrants.data?._embedded?.registrants || getRegistrants.data?.registrants || [];
const attendees = getAttendees.data?._embedded?.attendees || getAttendees.data?.attendees || [];

// Build attendee lookup by registrantKey
const attendeeMap = {};
attendees.forEach(a => {
  const key = a.registrantKey;
  if (!attendeeMap[key]) {
    attendeeMap[key] = {
      attended: true,
      duration_min: Math.round((a.attendanceTimeInSeconds || 0) / 60),
      join_time: a.joinTime ? new Date(a.joinTime).toLocaleTimeString([], {hour:'2-digit', minute:'2-digit'}) : '',
      leave_time: a.leaveTime ? new Date(a.leaveTime).toLocaleTimeString([], {hour:'2-digit', minute:'2-digit'}) : ''
    };
  } else {
    // Multiple sessions — sum durations
    attendeeMap[key].duration_min += Math.round((a.attendanceTimeInSeconds || 0) / 60);
  }
});

return registrants.map(r => ({
  name: `${r.firstName || ''} ${r.lastName || ''}`.trim(),
  email: r.email,
  registration_date: r.registrationDate ? new Date(r.registrationDate).toLocaleDateString() : '',
  status: r.status || 'Registered',
  attended: attendeeMap[r.registrantKey]?.attended ? 'Yes' : 'No',
  duration_min: attendeeMap[r.registrantKey]?.duration_min || 0,
  join_time: attendeeMap[r.registrantKey]?.join_time || '',
  high_intent: (attendeeMap[r.registrantKey]?.duration_min || 0) >= 30
}));
```

**Expected result:** Selecting a webinar from the dropdown loads a combined registrant and attendance table showing each registrant's name, email, whether they attended, and total attendance duration in minutes.

### 5. Build post-webinar follow-up workflow and finalize dashboard

Add a post-event follow-up section to the Retool app that enables the marketing team to act on attendance data immediately after a webinar. Add a Container component below the registrant table with three buttons: Mark High Intent (for attendees with more than 30 minutes of attendance), Send Replay Link (for no-shows), and Export to CSV. Each button uses a Select-all or row-checkbox mechanism to identify the target contacts. For the Mark High Intent action, create a query that calls your CRM API (HubSpot, Salesforce, or Pipedrive) with the selected attendee emails to update their lead score or add a tag. For the Send Replay Link action, trigger a Retool Workflow that sends a templated email via your email provider (SendGrid or Mailchimp) to the no-show registrant list with the webinar recording URL. The Export CSV action uses Retool's built-in table download functionality to export the filtered registrant data. At the top of the dashboard, add a Toggle to switch between Upcoming Webinars view and Past Webinars view — the past webinars query uses the toTime parameter set to now and fromTime set to a DateRangePicker's start date. For organizations running complex multi-webinar campaigns requiring custom follow-up sequences and multi-system integrations, RapidDev's team can help architect and build your Retool solution.

```
// Transformer: filter high-intent attendees for CRM update
const allAttendees = joinedAttendeeData.data || [];

// High intent = attended >= 30 minutes
const highIntentAttendees = allAttendees.filter(a => a.duration_min >= 30 && a.attended === 'Yes');
const noShows = allAttendees.filter(a => a.attended === 'No');

return {
  high_intent: highIntentAttendees.map(a => ({ email: a.email, name: a.name, duration: a.duration_min })),
  no_shows: noShows.map(a => ({ email: a.email, name: a.name })),
  high_intent_count: highIntentAttendees.length,
  no_show_count: noShows.length,
  total_registrants: allAttendees.length,
  attendance_rate: allAttendees.length > 0
    ? ((allAttendees.filter(a => a.attended === 'Yes').length / allAttendees.length) * 100).toFixed(1) + '%'
    : '0%'
};
```

**Expected result:** A complete webinar operations dashboard shows upcoming and past webinars, a combined registrant/attendee table for the selected webinar, stat components for attendance rate and high-intent count, and action buttons for CRM update and email follow-up workflows.

## Best practices

- Store the GoToWebinar organizer key in a secret configuration variable — it should never appear in browser-visible query URLs or Retool app logs.
- Handle GoToWebinar's HAL+JSON response format consistently: always extract data._embedded.webinars and data._embedded.registrants with optional chaining and array fallbacks to handle empty result sets gracefully.
- Join registrant and attendee data in a JavaScript query rather than displaying them in separate tables — the combined view showing registered + attended in one row is far more useful for follow-up workflows.
- Define high-intent attendance thresholds (e.g., watched 50%+ of the session duration) as a configurable Number Input component rather than hardcoding them — marketing teams need to adjust these thresholds per campaign.
- For multi-session webinars, sum attendance duration across all sessions per registrant rather than taking the first session only — multi-session events are common for training and certification webinars.
- Set up a Retool Workflow scheduled to run 24 hours after each webinar to automatically export attendance data to your CRM — this builds an automated post-event pipeline that runs without manual triggering.
- Cache the getUpcomingWebinars query for 10 minutes since webinar schedules change infrequently — avoid hammering the GoTo API every time a user opens the dashboard.

## Use cases

### Post-webinar attendee follow-up panel

Build a Retool app that runs after each webinar: select a completed webinar from a dropdown, load all registrants and their attendance status (attended, no-show), and display them in a Table with attendance duration, join time, and CRM link. Checkboxes let the marketing team select specific attendees for different follow-up sequences — a Send to High Intent button triggers a HubSpot workflow for attendees who watched more than 30 minutes, while a Send to No-Show button triggers a replay offer email for registrants who did not attend.

Prompt example:

```
Build a Retool app where users select a GoToWebinar event from a dropdown of recent webinars, see a Table of all registrants with columns for name, email, attended (yes/no), duration in minutes, and a CRM lookup link. Add checkboxes for bulk selection and buttons to tag selected contacts in HubSpot based on their attendance status.
```

### Webinar registration and analytics dashboard

Create a marketing dashboard that shows all upcoming GoToWebinar events with registration counts, registration trends over time, and conversion rate from email sends to registrations. For each webinar, a detail panel shows registration by day (useful for seeing if early bird deadlines work), registrant source breakdown if custom registration questions include a 'how did you hear about us' field, and a countdown to the event date. The dashboard refreshes daily and sends a Slack summary every Monday morning via a Retool Workflow.

Prompt example:

```
Build a Retool dashboard showing all upcoming webinars with registration count, days until event, and target capacity. Click a webinar to see a line Chart of daily registrations over time, a Table of all registrants with their registration date and custom field answers, and a Stat showing the registration rate to target. Include a Refresh button and a Share button that copies the webinar registration link.
```

### Webinar operations management panel

Build a centralized webinar management panel for an events team that handles multiple webinars per month. The panel lists all webinars in a Schedule view showing upcoming dates, sessions scheduled, and registration status. Clicking a webinar opens a detail sidebar with registrant management (view, manually add, or remove registrants), session configuration (check start time, co-organizer assignments), and post-event data (attendance rate, average time attended, poll responses). Export buttons generate CSV files for the sales team's follow-up outreach.

Prompt example:

```
Build a Retool app with a Table listing all GoToWebinar events for the current month, including title, date, registrant count, and status. Selecting a row shows a side panel with tabs for Registrants (with add/remove capabilities), Session Info (times, organizers), and Post-Event Data (attendance metrics and poll results) for completed webinars.
```

## Troubleshooting

### Registrants query returns empty _embedded object even though the webinar has registrants in GoToWebinar UI

Cause: The GoToWebinar API uses HAL+JSON format and the _embedded field may be missing or structured differently depending on the page size and whether results exist. An empty webinar returns an empty _embedded rather than an empty array.

Solution: Update your transformer to handle both the _embedded.registrants path and a direct registrants path using optional chaining: (data._embedded?.registrants || data.registrants || []). Also add the page query parameter set to 0 and size set to 200 to ensure full pagination is requested rather than relying on defaults.

```
// Safe extraction with fallback
const registrants = (
  data?._embedded?.registrants ||
  data?.registrants ||
  []
);
```

### OAuth token expires and queries start returning 401 after one hour

Cause: GoTo OAuth access tokens have a 1-hour expiration. Without the access_type: offline parameter configured during OAuth setup, no refresh token is issued, requiring re-authorization every hour.

Solution: In the GoToWebinar REST API Resource settings, verify the additional OAuth parameters include access_type: offline. If the resource was created without this parameter, delete and recreate it, or disconnect and reconnect the OAuth authorization — this time with access_type: offline which triggers GoTo to issue a refresh token. Retool will automatically use the refresh token to obtain new access tokens without user intervention.

### Attendees query returns 404 for a webinar that shows in the upcoming webinars list

Cause: The attendees endpoint only returns data for completed webinar sessions — a webinar that has not occurred yet has no attendance records.

Solution: Add status-based conditional logic in the Retool app: check the webinar's start time against the current time before triggering the attendees query. Only call the attendees endpoint when the selected webinar's start date is in the past. Display a message like 'Attendance data available after the webinar date' for upcoming sessions instead of triggering the query.

```
// Conditional check before triggering attendees query
const webinarStartTime = new Date(selectedWebinar.start_date);
const now = new Date();
const isCompleted = webinarStartTime < now;

// Use this boolean to control query visibility in the Retool app
```

## Frequently asked questions

### Can I create a new webinar from Retool using the GoToWebinar API?

Yes. Send a POST request to /G2W/rest/v2/organizers/{organizerKey}/webinars with a JSON body containing the subject, description, timeZone, and times array (with startTime and endTime in ISO 8601 UTC format). The response contains the webinarKey and registration URL for the newly created webinar. You can also configure advanced settings like panelist and co-organizer emails in the same request. After creation, trigger getUpcomingWebinars to refresh the list and display the new webinar immediately.

### How do I add a registrant directly from Retool (not through the GoToWebinar registration page)?

Send a POST request to /G2W/rest/v2/organizers/{organizerKey}/webinars/{webinarKey}/registrants with a JSON body containing firstName, lastName, email, and any required custom registration field responses. The API validates the email format and returns a registrantKey and joinUrl for the newly registered attendee. This is useful for bulk registering contacts from your CRM who should be invited to a webinar without going through the public registration form.

### Does the GoToWebinar API provide recording URLs for completed webinars?

Yes, but through the sessions endpoint, not the webinars endpoint. Query GET /G2W/rest/v2/organizers/{organizerKey}/webinars/{webinarKey}/sessions to list all sessions for a completed webinar. Each session object includes a recordingAssetKey if a recording was made. To get the actual recording URL, use this key with GoToWebinar's recording management endpoints or retrieve it from the GoToWebinar UI. Recording availability depends on your GoToWebinar subscription plan — not all plans include cloud recording.

### Can I access poll and survey responses from GoToWebinar in Retool?

Yes. GoToWebinar exposes poll and survey data through the session endpoints. After a session completes, query GET /G2W/rest/v2/organizers/{organizerKey}/webinars/{webinarKey}/sessions/{sessionKey}/polls for poll results and ../surveys for survey responses. These endpoints return per-question response aggregates and, for attendee-level responses, you can correlate the data with the attendee registrantKey. Poll data is particularly useful for segmenting follow-up outreach based on attendee interest or qualification questions asked during the webinar.

---

Source: https://www.rapidevelopers.com/retool-integrations/gotowebinar
© RapidDev — https://www.rapidevelopers.com/retool-integrations/gotowebinar
