# Web Example: Engagement-Aware State

```javascript
await zoomSdk.config({
  version: "0.16.0",
  capabilities: [
    "getRunningContext",
    "getEngagementContext",
    "getEngagementStatus",
    "onEngagementContextChange",
    "onEngagementStatusChange",
  ],
});

const stateByEngagement = new Map();
let currentEngagementId = "";

function ensureState(id) {
  if (!stateByEngagement.has(id)) {
    stateByEngagement.set(id, { notes: "", formDraft: {} });
  }
  return stateByEngagement.get(id);
}

async function hydrate() {
  const [ctx, status] = await Promise.all([
    zoomSdk.callZoomApi("getEngagementContext"),
    zoomSdk.callZoomApi("getEngagementStatus"),
  ]);
  currentEngagementId = ctx?.engagementContext?.engagementId || "";
  if (currentEngagementId) ensureState(currentEngagementId);
  render(currentEngagementId, status?.engagementStatus?.state);
}

zoomSdk.addEventListener("onEngagementContextChange", (evt) => {
  currentEngagementId = evt?.engagementContext?.engagementId || "";
  if (currentEngagementId) ensureState(currentEngagementId);
  render(currentEngagementId);
});

zoomSdk.addEventListener("onEngagementStatusChange", (evt) => {
  const state = evt?.engagementStatus?.state;
  if (state === "end" && currentEngagementId) {
    stateByEngagement.delete(currentEngagementId);
  }
  render(currentEngagementId, state);
});

hydrate();
```

## Campaign SDK Ready Gate

```javascript
window.addEventListener("zoomCampaignSdk:ready", () => {
  if (!window.zoomCampaignSdk) return;
  window.zoomCampaignSdk.show();
});
```

