Discourse Zoom

:discourse2: Summary Discourse Zoom empowers Discourse administrators and users with a paid Zoom subscription to schedule, manage, and participate in Zoom webinars directly from their Discourse platform.
:hammer_and_wrench: Repository Link https://github.com/discourse/discourse-zoom
:open_book: Install Guide How to install plugins in Discourse


This plugin integrates Zoom webinars into a Discourse instance. Zoom webinars can be associated with topics, Discourse users can register for webinars and join them when they start.

:warning: Due to Zoom deprecating JWT authentication, as of August 1st 2023, the plugin’s authentication mechanism has changed from JWT (now deprecated, Zoom will remove on September 1st) to Server-to-Server OAuth. Existing users of the plugin need to update their settings.


  • When a Zoom webinar starts, the “Register” button automatically switches to “Join”, and clicking it launches the webinar using the Zoom SDK in a dedicated endpoint inside your Discourse community
  • Automatically reminds webinar registrants N minutes before the event (N is configurable in the plugin settings, by default reminders are turned off)
  • Administrators can add panelists to a webinar in Discourse
  • Administrators can add a link to video recordings of the webinar in Discourse, which is then displayed to users after the event has ended
  • Zoom event hosts and panelists are associated with Discourse user accounts


To use the Discourse Zoom plugin, you first need to install it in your Discourse instance and configure it with your Zoom Server-to-Server OAuth app credentials. Once the plugin is set up, you can create a new Zoom webinar by creating a new topic and associating it with the webinar. Users can then register for the webinar directly from the topic.


Step 1: Create a Server-to-Server OAuth app in the Zoom Marketplace

To get started, you’ll need to create a Server-to-Server OAuth app in the Zoom Marketplace.

Step 2: Install the plugin in your Discourse instance

You can install the plugin in your Discourse instance by following the instructions here.

Step 3: Configure the plugin

Once the plugin is installed, go to your Discourse settings and check the zoom enabled checkbox. Then, copy and paste the zoom s2s account id, zoom s2s client id, and zoom s2s client secret site settings from your app’s credentials tab.

Step 4: Enable event subscriptions

Under the Feature tab of your Zoom Server-to-Server OAuth app, enable event subscriptions. Under Event Types, load the Webinar tab and check all the events in it. If you can’t see webinar permissions, check how to enable permissions.

Set the Event notification endpoint URL to https://YOURSITE.com/zoom/webhooks/webinars.json.

Click on validate then click on save.

Step 5: Create a Meeting SDK App

Under the App Credentials tab in your Meeting SDK App, copy and paste the Client ID/ SDK key into the zoom sdk key field, and the Client Secret/SDK secret into the zoom sdk secret field.

Next, under the App Credentials, you will find the Redirect URL for OAuth and the Add Allow List. Copy and paste the following link https://YOURSITE.com/auth/oauth2_basic/callback.

Step 6: Activate the SDK App

Go to the SDK Activation tab and in the Add URL, copy and paste the provided URL in your browser to activate the SDK app. Currently, we don’t use the provided OAuth by the Meeting SDK, but setting it up is required.

Make sure your app is activated. To do this, click on Manage and check the Status column.


The plugin only works with webinars that do not require registration in Zoom.

Notice about breaking Changes

Due to deprecations in the Zoom API, old instances of the plugin will need to be configured following the steps mentioned in this post.

:discourse2: Hosted by us? This plugin is available on our Enterprise plans.


Thanks so much for working on this, great feature!

I was able to install the plugin, create the JWT app in Zoom, and configure my discourse as described.
However, I am running into problems when using the Zoom Webinar button in the composer to associate a scheduled meeting with the post.


It would be great if you could please add an explanation what exactly one has to enter in the text input under “Add Webinar” . Neither the meeting ID or full URL seem to work for me.

Another minor issue I noticed: The repository URL linked to in the “Plugins” page of the admin dashboard points to https://github.com/discourse-org/discourse-zoom, whereas it should be linking to https://github.com/discourse/discourse-zoom


Interesting concept, and looks like a nice experience for community members!

I’m curious if there’s been any thought yet to allowing a more generic (vendor-agnostic) workflow with this plugin; basically to offer the same embedding of a countdown timer to a specific time and date, specifying a host and/or panelist, link to the webinar URL, later links to recordings, etc.

Jiti (open source) would be the example that I had in mind but there are obviously several options in this space.


You need to enter the webinar ID. In your site’s logs in /logs, you should be able to see more details if it still can’t add the event in the modal window. I also fixed the URL issue you mentioned, thanks for reporting that.

Unfortunately, no, this currently does not provide a vendor-agnostic workflow. The Zoom API calls are abstracted though, so it’s possible to add support for another vendor with a bit of effort (although, the plugin would need to be renamed to something less zoom-y).


Hi Penar, thanks for the great plugin this will be really useful! I just tested it out and setup went smoothly. A few issues I’ve noticed:

  • When I create a topic with the webinar I get this error, but if I refresh the page it does create the topic and everything seems to be okay.

I get this in the logs

/var/www/discourse/plugins/discourse-zoom/app/jobs/scheduled/send_webinar_reminders.rb:18:in `block (2 levels) in execute'
activerecord-6.0.1/lib/active_record/relation/delegation.rb:85:in `each'
activerecord-6.0.1/lib/active_record/relation/delegation.rb:85:in `each'
/var/www/discourse/plugins/discourse-zoom/app/jobs/scheduled/send_webinar_reminders.rb:12:in `block in execute'
activerecord-6.0.1/lib/active_record/relation/delegation.rb:85:in `each'
activerecord-6.0.1/lib/active_record/relation/delegation.rb:85:in `each'
/var/www/discourse/plugins/discourse-zoom/app/jobs/scheduled/send_webinar_reminders.rb:11:in `execute'
/var/www/discourse/app/jobs/base.rb:232:in `block (2 levels) in perform'
rails_multisite-2.1.1/lib/rails_multisite/connection_management.rb:64:in `with_connection'
/var/www/discourse/app/jobs/base.rb:221:in `block in perform'
/var/www/discourse/app/jobs/base.rb:217:in `each'
/var/www/discourse/app/jobs/base.rb:217:in `perform'
/var/www/discourse/app/jobs/base.rb:279:in `perform'
mini_scheduler-0.12.2/lib/mini_scheduler/manager.rb:86:in `process_queue'
mini_scheduler-0.12.2/lib/mini_scheduler/manager.rb:36:in `block (2 levels) in initialize'
  • The biggest problem is that I don’t see a join button when the meeting is live:

  • FYI the countdown background doesn’t follow the theme, I had to change this to match my dark theme as it was just white:
.webinar-header .countdown .pill {
    background: #485769;

Question, when someone registers will they only get a notification on the site and no email? Or will they get an email if they are not currently on the site?



Thanks David,

Did you complete the event subscription steps? That’s a webhook from the Zoom API, and it’s used to switch the Registered button to a “join now” button as soon as an event starts.

They will get a PM which means they will get an email if their settings are such that PMs send them emails.

I will look into the other two issues shortly.


I did all that. This is probably a stupid question, but under content security policy script src you have https://source.zoom.us, is source supposed to be replaced with something else? Possibly the name of the app?

1 Like

Hmm. And you checked all the boxes in the webinar tab? Should look like this:

No, that’s fine, in any case your setup hasn’t gotten to that screen yet.

1 Like

Yeah I have those checked, what should my Event notification endpoint URL be in the app?

1 Like

It should be https://yoursite.com/zoom/webhooks/webinars.json – I see that my instructions above do not include that detail, sorry about that. Hopefully that’ll be the missing piece.


That did it. Thank you!


I wasn’t very clear, just for clarification I am still having the problem with Username, etc. can’t be blank error with nothing in the logs now, everything else is working okay.


I looked into this issue @davidkingham, it looks like the webinar you’re creating in Zoom has no host, or the API is not returning those details for the host. The plugin tries to match the Zoom user account (via email) to a Discourse account and if it doesn’t find an account, it creates a staged user in Discourse.

Either your webinar has no host set or the API call to get the user object for the host is returning empty.


That makes sense, I was using a different email for each. I changed the email in zoom to match my user in discourse. This helped to show the upcoming webinars in the list when adding a webinar to the topic, which it wasn’t doing before, but I still get the ...can't be blank error. Does the email need to match the user that is creating the topic, or the admin email?

Also, if I delete the topic to retry, it doesn’t allow me to add that webinar to another topic because it thinks the webinar is associated with another topic already, even though it’s been deleted.


I wonder whether you are getting an email back for the user from Zoom at all. Maybe the API key does not have the correct scopes set?

This is the API call that I think is not returning data: https://marketplace.zoom.us/docs/api-reference/zoom-api/users/user (or maybe your user’s status is pending?)

Yes, confirmed. There might be a fix coming for this soon, for the moment, you can go to the deleted topic and from the topic’s admin menu you can click on Remove Webinar.


Here’s the call log when I get the error, looks like it’s hitting a rate limit

endpoint: "https://api.zoom.us/v2/users/VI4TWwOvT-SKaycEEMws8w",
response_headers: [
"Set-Cookie: cred=73B256F7AFD1CC7FEA83613B92876F28; Path=/; Secure; HttpOnly"
date_time: "2020-03-25 11:42:17",
method: "GET",
request_body: "N/A",
response: {
code: 429,
message: "You have reached the maximum per-second rate limit for this API. Try again later."
request_headers: [
"authorization: ******",
"connection: close"
request_params: [
http_status: "429"

That is quite restrictive… AFAIK it’s only making 2 API calls, one to get the webinar, and the other to get the webinar host’s details (in fact, in an ideal world, the host’s details should have been included in the first API call).

You could try raising this in Zoom’s developer forum.


I posed the question here, based on other questions I don’t have much faith that they will help.

Small suggestion for the plugin, I would like to see the panelist list display like the host. So putting the avatar below the title with their name next to it. Right now the panelist is not very obvious with just the small avatar.


Is there any possibility of adding meeting support w/out registration to this plugin as well as webinars? Great work!


Now that Zoom requires a password for all meetings/webinars I think the plugin is broken. I tried creating a webinar and when I join it gives this error Your connection has timed out and you cannot join the meeting. Verify your network connectivity and try again.