Coming soon
Monitor Zoom Workplace meeting quality, availability, and user license capacity by ingesting metrics and structured logs from the Zoom REST API into Dynatrace.
The extension polls five Zoom REST API v2 endpoints and, per collection cycle:
ZOOM_ACCOUNT, ZOOM_ROOM, and ZOOM_PHONE_DEVICE nodes with their is_part_of edges on Smartscape on Grail.self_monitoring feature set reports Zoom API success/failure counts and rate-limit hits as sfm.zoom.* metrics.The five endpoints it calls:
| Data group | Endpoint | Collection tier | Rate-limit class used | Feature set |
|---|---|---|---|---|
Meeting overview |
| Real time | Resource-intensive |
|
Meeting participant QoS |
| Real time | Heavy |
|
Zoom Room health |
| Real time | Resource-intensive |
|
User & license inventory |
| Standard | Medium |
|
Phone device inventory |
| Standard | Medium |
|
The meeting QoS call is also made (independently of those three feature sets) whenever the meeting & participant activity logs option is on.
Five endpoints, but more than five calls per cycle: GET /users is issued three times (once each for active, inactive, and pending, because Zoom does not accept status=All), GET /phone/devices twice (assigned and unassigned), and the QoS endpoint once per live meeting. Every page of a paginated response counts as a separate call as well.
A Zoom Pro, Business, or Enterprise account. Business+ is recommended because the Dashboard APIs this extension depends on are gated by plan, and higher tiers carry higher rate limits.
Admin-level access to the Zoom App Marketplace to create a Server-to-Server OAuth app, with these scopes:
| OAuth scope | Needed for |
|---|---|
| Meeting overview ( |
| Meeting QoS and participant CPU, and the participant activity logs |
| Zoom Room health |
| User license & account capacity |
| Phone device status |
A Dynatrace ActiveGate running the Extensions Execution Controller (minEECVersion 1.313.0), with outbound HTTPS access to zoom.us (token endpoint) and api.zoom.us (API). A proxy can be configured if direct access is not available.
A Dynatrace environment on version 1.345.0 or later (minDynatraceVersion), which is also what the Smartscape 2.0 node/edge extraction requires.
Only the meeting-overview scope is validated at activation time. The other four degrade at runtime. If a scope is missing, that endpoint returns 403, the extension logs it and reports a non-OK endpoint status for that feature set, and the rest of the collection keeps working.
This extension works with the Zoom REST API v2 and delivers complete, out-of-the-box observability for the following Zoom data groups:
For these data groups, everything is ready to use from the moment a monitoring configuration is saved. Metrics, dashboards, alerts, and Smartscape topology are all populated for you.
Which data groups reach Dynatrace is determined by the feature sets you enable and the OAuth scopes you grant, not by the extension, so you always stay in control of what you collect and what it costs in Zoom API calls.
This extension also has the following constraints:
multiObject: false with tenant scope, so a single Dynatrace environment monitors a single Zoom account.Activation has four parts. Activate the extension from Dynatrace Hub, create the Zoom OAuth app, create the monitoring configuration, and verify that data is flowing. The prerequisites are listed under Requirements.
Activate the Zoom Workplace extension in the Hub app. Upon activation, the extension deploys all its assets, including metric collection code, metric and topology definitions, the OpenPipeline settings, dashboards and alert templates.
The OpenPipeline metrics source is bound to this extension (sourceType: extension, source: com.dynatrace.extension.zoom-workplace) and statically routed to the Zoom Smartscape Metrics Pipeline. There is no dynamic route to add by hand. The zoom.* metrics reach the Smartscape pipeline automatically as soon as the extension starts reporting.
Once activated, everything that ships with the extension (the dashboards, the alert templates, and the OpenPipeline pipeline) is listed on the extension's Content page.
All five collection groups share a single Zoom Server-to-Server OAuth app. Create it once:
Add a monitoring configuration, choose the ActiveGate group that will run it, and fill in the fields below.
| Field | Required | Description |
|---|---|---|
Zoom Account ID ( | Yes | Account ID from the OAuth app's App Credentials tab. |
Use credential vault ( | No | When on, the Client ID and Client Secret are read from a Dynatrace credential vault entry instead of being typed in. Default: off. |
Vault credentials ( | Only when the vault is used | A |
OAuth Client ID ( | Only when the vault is not used | Client ID from the OAuth app. |
OAuth Client Secret ( | Only when the vault is not used | Client Secret from the OAuth app. Stored as a secret and used only in the HTTP Basic header of the token request. Never written to the log. |
| Field | Default | Range | Applies to |
|---|---|---|---|
Real time interval ( |
| 30-300 |
|
Standard interval ( |
| 60-3600 |
|
A value outside its range, or one that is not a number, is logged and replaced with the default rather than failing the configuration. The self_monitoring metrics are flushed on a fixed 60-second cadence, independent of both intervals.
| Field | Default | Description |
|---|---|---|
Enable meeting & participant activity logs ( |
| Sends |
Enable debug logging ( |
| Raises the extension log level to |
Proxy ( | not set | Optional |
OAuth token URL ( |
| For Zoom Workplace Gov accounts, use the Gov-specific token endpoint instead of the standard one. |
API base URL ( |
| For Zoom Workplace Gov accounts, use the Gov-specific API base URL instead of the standard one. |
meeting_activity_logs is not a display-only switch. When it is on, every real-time cycle calls GET /metrics/meetings/{meetingId}/participants/qos for each live meeting to source the participant log, even if meeting_audio_qos, meeting_video_qos, and participant_cpu_usage are all disabled. If you turned the QoS feature sets off to control API volume, turn this off as well. Zoom Room issue logs behave differently. They have no separate toggle and simply follow the zoom_room_health feature set, because that feature set already fetches the data they are built from.
Select the feature sets you want on the same configuration screen. default is always active. The rest are opt-in per monitoring configuration.
On save, the extension runs a pre-flight check (fastcheck) that:
account_id, Client ID, and Client Secret are all present, including the case where the credential vault is selected but injected no username/password, which is reported as a distinct error instead of silently producing no data.GET /metrics/meetings?type=live&page_size=1 with today's date as both from and to, as a lightweight validation call.A green status on the monitoring configuration means all three passed. Data appears on the dashboards within one or two collection cycles.
The Zoom Workplace extension collects metrics and topology for:
Metrics are reported under the zoom.* namespace and collected from the following feature sets (enable them per monitoring configuration during activation). The default feature set is always on and reports active meetings, per-meeting participant counts, and average meeting duration:
zoom_room_health): Room availability, per-component hardware health, and open issue countsuser_license_capacity): User inventory by license type, department, and activation statusphone_device_status): Zoom Phone device connectivity by sitemeeting_audio_qos): Per-participant audio bitrate, latency, jitter, and packet lossmeeting_video_qos): The same for video, plus resolutionparticipant_cpu_usage): Per-participant Zoom-client CPU min/avg/maxself_monitoring): Zoom API success/failure counts and rate-limit hits, reported as sfm.zoom.*The extension is packaged with four dashboards, two Live pages (Rooms, and Users & Phone Devices) and two Trends pages (Meeting Quality, and API Monitoring), that serve as a starting point for data analysis, and with seven alert templates that ship inactive and can be enabled from the extension's Content page.
Zoom enforces API rate limits at the account level, shared by every OAuth app and integration connected to that account, not per API key and not per app. The extension therefore paces itself proactively rather than waiting to be rejected.
A single token-bucket registry is shared by every collector and every QoS worker thread, so it tracks the total request rate across the extension. It is sized for Zoom's Pro plan and deliberately runs at 80% of each published ceiling to leave margin for network timing:
| API class | Pro-plan ceiling | Used by |
|---|---|---|
Light | 30 req/s | — (reserved) |
Medium | 20 req/s |
|
Heavy | 10 req/s |
|
Resource-intensive | 10 req/minute |
|
Resource-intensive is the strictest of the four, because it is a per-minute limit rather than a per-second one. Zoom also applies a daily cap shared between the Heavy and Resource-intensive classes (30,000 requests/day on Pro). That cap is not paced proactively, but handled reactively when Zoom reports it.
When Zoom rate-limits anyway (because something else on the account is also making requests), the extension reads the X-RateLimit-Type header and reacts accordingly:
| Situation | Handling |
|---|---|
| Wait until |
| Parse |
| Force a single token refresh and retry once. A second |
| Fail immediately due to an insufficient OAuth scope. Not retried. |
| Fail immediately. Not retried. |
| Skipped silently on the QoS call. This is the expected race when a meeting ends between the list call and the QoS call. |
| Retry up to 3 times, backing off 2 s → 4 s → 8 s. |
Malformed JSON | Retry up to 3 times with the same backoff. |
Every collector treats a failed endpoint as a skipped cycle rather than a crash. It logs the failure with a DEC: code, reports the appropriate endpoint status, and lets the next scheduled cycle try again.
All five endpoints are cursor-paginated via next_page_token, which expires after 15 minutes. If a cycle's pagination exceeds that window, the extension restarts once from page 1. A restart that also exceeds it is reported as an error. Page sizes are 300 for meetings, rooms, users, and phone devices, and 10 for the QoS endpoint (Zoom's maximum).
Because Zoom exposes no bulk multi-meeting QoS call, each live meeting is fetched individually. A bounded pool of 8 workers drains this queue, paced against the shared Heavy bucket, and each meeting's results are reported and released as its fetch completes, so a large account's full QoS payload is never held in memory at once.
Zoom returns user_qos in ascending time order, and the last element is the current, possibly still-incomplete minute. The extension reports the second-to-last element (the most recent fully elapsed minute) and stamps the metric at that sample's own timestamp rather than at collection wall-clock. A participant with fewer than two samples is skipped, and individual blank or unparseable QoS fields are skipped rather than reported as false zeros.
The extension models its estate twice, and both models are installed automatically.
Declared in extension.yaml and built directly from metric dimensions:
| Entity type | Display name | ID pattern | Created from |
|---|---|---|---|
| Zoom Account |
| any |
| Zoom Room |
|
|
| Zoom Phone Device |
|
|
Both zoom:room and zoom:phone_device are related to zoom:account with a PART_OF relationship, mirroring how Zoom organizes its estate.
Built by the bundled Zoom Smartscape Metrics Pipeline, which extracts nodes and edges from the zoom.* metrics as they arrive, so the map stays live rather than static:
| Node type | Identified by | Named from | Upserted by |
|---|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
Each Zoom Room and Zoom Phone Device node carries an is_part_of static edge to its Zoom Account node. Every zoom.* metric is also stamped with the Zoom Account node ID, and the room metrics (zoom.rooms, zoom.room.component.status) with the Zoom Room node ID, so metrics attach to the right node.
The account node is upserted from zoom.meetings.active, which belongs to the always-on default feature set, so the account node exists as long as the extension is reporting at all. Room and phone device nodes require their respective feature sets to be enabled.
To explore the topology, open the Smartscape app and filter for Zoom Account, Zoom Room, or Zoom Phone Device, then select an entity to walk its connections. Allow a few minutes after the first collection cycle.
There is no charge to use the extension. You are only charged for the data that the extension ingests.
The Zoom Workplace extension ingests metrics and structured logs. The extracted metrics consume Davis Data Units (DDUs) (Dynatrace classic license) or Metrics powered by Grail (DPS), according to your license model.
In the Dynatrace Platform Subscription, metric ingestion consumes Metrics powered by Grail according to the number of ingested metric data points.
The following formula provides approximate data points ingested per minute, assuming all feature sets are enabled and the default collection intervals.
(( 3 unique meeting metrics * dimension combinations ) -- default (always on)+ ( 5 unique audio QoS metrics * dimension combinations ) -- meeting_audio_qos+ ( 5 unique video QoS metrics * dimension combinations ) -- meeting_video_qos+ ( 3 unique CPU metrics * dimension combinations ) -- participant_cpu_usage+ ( 3 unique Zoom Room metrics * dimension combinations ) -- zoom_room_health+ ( 1 unique user metric * dimension combinations ) -- user_license_capacity (every 5 min)+ ( 1 unique phone device metric * dimension combinations ) -- phone_device_status (every 5 min)+ ( 3 unique self-monitoring metrics * dimension combinations ) -- self_monitoring) * 60 minutes * 24 hours * 365 days data points per year
A "dimension combination" is a distinct set of values across a metric's dimensions. Omit any line for a feature set you don't enable.
In practice, each combination maps onto one real object (a meeting, participant, Zoom Room, user, or phone device) because every metric carries an identity dimension (meeting_id, participant_id, room_id, user_id, device_id). Only two dimensions multiply that count, direction (input/output) on the QoS metrics and component (six values) on zoom.room.component.status. So cost scales with the size of your live Zoom estate and how often you poll it, not with the number of metric keys or dimensions.
For the activity logs, regular consumption applies. See Log Analytics. Activity logs add one record per live meeting, one per participant with a QoS sample, and one per open Zoom Room issue, per real-time cycle.
In the classic licensing model, metric ingestion consumes Davis Data Units (DDUs) at the rate of .001 DDUs per metric data point. Multiply the above formula for annual data points by .001 to estimate annual DDU usage.
For the activity logs, regular consumption applies. See DDU consumption for Log Management and Analytics or DDUs for Log Monitoring Classic. Activity logs add one record per live meeting, one per participant with a QoS sample, and one per open Zoom Room issue, per real-time cycle.
DDUs consumed by this extension are eligible for the free tier included with every host.
Beyond metrics, the extension sends three structured log streams to Grail. Logs carry the per-meeting, per-participant, and per-room-issue detail that would otherwise explode metric cardinality, and they stay queryable with DQL.
| Log source | One record per | Emitted by | Gated by |
|---|---|---|---|
| live meeting, per real-time cycle | meeting list ( |
|
| participant with a reportable QoS sample, per real-time cycle | QoS fan-out ( |
|
| entry in a room's | Zoom Room poll ( |
|
Every record carries timestamp, log.source, event.type, content, dt.extension.name, and dt.extension.config.id, plus the fields below. zoom.meeting.activity and zoom.participant.activity records are flushed to the platform in batches of 1000 rather than accumulated for a whole cycle, so the log buffer never scales with the account's meeting × participant count. zoom.room.issue records are flushed once, at the end of the Zoom Room poll.
zoom.meeting.activityevent.type is meeting_sample.
| Field | Description |
|---|---|
| Zoom account ID |
| Meeting ID |
| Host's department |
| Host's license type |
| Participant count at sample time |
| Zoom's own audio quality rating for the meeting |
| Zoom's own video quality rating for the meeting |
zoom.participant.activityevent.type is participant_qos_sample.
| Field group | Fields |
|---|---|
Identifiers |
|
Client context |
|
Audio quality |
|
Video quality |
|
CPU |
|
Media socket breaks |
|
Diagnosis |
|
zoom.room.issueevent.type is room_issue.
| Field | Description |
|---|---|
| Zoom account ID |
| Which room |
| The room's normalized health state at sample time |
| The raw issue text Zoom reported |
The activity logs deliberately exclude PII. user_name, email, ip_address, mac_addr, and pc_name are never written to zoom.participant.activity, and the meeting record carries the host's department and license type but not their name or email. Note that this is a property of the logs. The QoS metrics do carry a participant_name dimension, and zoom.meetings.participants carries a host dimension, because the dashboards and alerts identify who is affected.
The Live Rooms dashboard's Recent Room Issues tile reads zoom.room.issue directly. The other two streams are available for ad-hoc DQL in Notebooks.
The Zoom Account entity is built from zoom.meetings.active, which belongs to the always-on default feature set, but that metric is only reported when at least one meeting is live. On a quiet account, wait until a meeting starts. Zoom Room and Zoom Phone Device entities additionally require the zoom_room_health and phone_device_status feature sets. No OpenPipeline dynamic route needs to be created. The metrics source is statically routed to the Smartscape pipeline as part of activation.
That dashboard needs meeting_audio_qos, meeting_video_qos, and participant_cpu_usage, all of which ship disabled because each costs one Heavy API call per live meeting. Enable them on the monitoring configuration. The dashboard's header tile states the same requirement.
It reads sfm.zoom.*, which is only collected while the self_monitoring feature set is enabled. Counting is skipped entirely when the feature set is off, so there is no back-fill after enabling it. Data starts at the next 60-second flush.
The extension reports the second-to-last user_qos sample (the most recent fully elapsed minute) and skips participants with fewer than two samples. A participant who has been in a meeting for less than roughly two QoS minutes produces no QoS metrics yet. This is deliberate, because the newest sample is the current, still-incomplete minute and would report artificially low values.
Zoom does not return every QoS field for every sampled minute. Fields it leaves empty are simply not reported, so a chart gap means "Zoom did not report this field for this minute", not "the value was 0". This is most visible on sparsely populated media fields.
Alert templates ship disabled. Enable the ones you want from the extension's Content > Alert template page. Enabling one adds it to Anomaly Detection. Then check two things. First, that the feature set the alert depends on is actually enabled. Second, that you have not raised real_time_interval or standard_interval without widening the templates' sliding windows. Each template evaluates one-minute buckets, so a longer poll interval leaves most buckets in the window empty.
The Live pages open on a fixed 5-minute window on purpose, to show current state. Widening the timeframe makes their directory tables report an average across the whole selected range instead of the latest reading. Use the Trends dashboards for longer ranges.
Zoom's limits are account-wide and shared with every other integration on that account, so another tool can consume the quota. Enable self_monitoring and check sfm.zoom.api.rate_limit.hit, split by limit_type and api_class, on the API Monitoring dashboard. Daily-limit hits on the Heavy or Resource-intensive class almost always mean the QoS fan-out. See the next question. Note also that the extension's pacing is pinned to Pro-plan limits, so on a Business+ account it stays well under what you are entitled to.
In order of impact:
meeting_audio_qos, meeting_video_qos, and participant_cpu_usage, and turn off meeting_activity_logs. Otherwise the per-meeting QoS call still runs to source the participant logs.real_time_interval toward its 300-second maximum, remembering to widen the alert templates' sliding windows to match.standard_interval for the user and phone inventory, which rarely changes minute to minute.