What This Tool Is
A real-time BCDR operations console for Datto Backup — surfaces protected asset status, backup job health, screenshot verification, storage utilization, and appliance state across all managed clients.
The Datto Backup BCDR Console is a single-page HTML dashboard that connects to the Datto Backup REST API v1 (base URL: https://{partner}.dattobackup.com/api/v1/). It gives MSP NOC technicians a unified view of all BCDR assets without navigating the Datto partner portal.
The dashboard replaced an incorrectly-submitted file that was wired to the Datto RMM API (devices, patches, job queue) — an entirely different product and endpoint set. This console is rebuilt from scratch against the actual Datto Backup API schema. All KPIs, panels, mock data fields, and modal detail all match the real API response shapes documented at portal.dattobackup.com/integrations/api.
In demo mode all data is generated by deterministic mock functions whose object schemas exactly mirror the real API responses. Switching to live data requires only configuring the proxy and flipping DEMO_MODE = false.
NOC Technicians — Monitor backup success rates, triage failures, trigger manual backups, and check screenshot verification without logging into the Datto portal. Alert feed surfaces the most critical items immediately.
Backup Administrators — Storage view and appliance view give a full picture of local and offsite utilization across all SIRIS, ALTO, and Cloud devices.
Service Delivery Managers — KPI strip shows overall backup success rate, failure count, and screenshot pass rate suitable for morning stand-up or wall-board display.
Engineers — API-audited wiring and documented limitations make this the ground truth for what the Datto Backup API can and cannot surface in an integration.
API Audit Findings
The originally submitted file was wired entirely to the Datto RMM API. Every endpoint, KPI, and data field has been corrected to match the Datto Backup (BCDR) API.
dashboard-datto-backup.html) was a Datto RMM console re-titled as a backup tool. None of the following original endpoints exist in the Datto Backup API: GET /devices (RMM agents), GET /patches (patch management), GET /jobs (job queue), GET /sites (RMM sites). Every single KPI, table, and panel has been replaced.
| Original (RMM — Wrong) | Corrected (Backup API — Correct) | Notes |
|---|---|---|
| /devices → device table | /bcdr/asset → protected assets | Completely different resource. BCDR assets = backed-up agents, not RMM-managed endpoints. |
| /patches → patch pending | /bcdr/asset → lastSuccessfulBackup | No patch concept in Backup API. Patch pending KPI replaced by backup failure count. |
| /jobs → job queue view | Derived from /bcdr/asset state | No job queue endpoint in Backup API. Retry actions call device-level controls only. |
| /sites → sites view | /bcdr/device → appliances view | Backup "sites" are represented as appliances (SIRIS/ALTO), not named site objects. |
| /reports → charts | /bcdr/asset/backupVolumes → storage | Storage volume detail is the primary reporting surface in the Backup API. |
| KPI: Total Devices / Online / Offline | KPI: Protected Assets / Backups OK / Failures | Core metric is backup success, not device online status. |
| KPI: Patch Pending / Active Sites | KPI: Screenshot Fails / Local Storage TB / Appliances | BCDR-specific metrics: screenshot verification and storage are primary health indicators. |
| KTC home bar + HOME link present | Removed per suite directive | Demo bar and home link stripped. Only console name shown in topbar. |
| Button / Action | API Endpoint | Fulfillable? | Notes |
|---|---|---|---|
| Force Backup (all) | POST /bcdr/asset/{sn}/actions | Partial | API accepts per-asset action triggers. Bulk "all" requires client-side iteration. |
| Force Backup (single) | POST /bcdr/asset/{sn}/actions | Yes | Documented in Datto Backup API. Requires asset serialNumber. |
| Restore Snapshot | Portal only — no REST endpoint | No | Restores must be initiated in the Datto partner portal. No REST restore endpoint exists. |
| Check Screenshot | POST /bcdr/asset/{sn}/actions | Partial | Screenshot verification can be triggered via actions endpoint. Status read from GET /bcdr/device/screenshots. |
| Enable Ransomware | PATCH /bcdr/asset/{sn} | Yes | ransomwareDetectionEnabled is a patchable field on the asset. |
| Retry failed backup | POST /bcdr/asset/{sn}/actions | Yes | action type: "startBackup" |
| Resolve Alert | N/A — local state only | Local | No alert acknowledgment endpoint. Resolved state is client-side only until next poll. |
| Approve All (patches) | Removed — not a Backup API concept | Removed | Patch approval belongs to Datto RMM, not the Backup API. Panel has been removed. |
Integration Status
Current state of each layer between the browser and the Datto Backup API.
DEMO_MODE = false in the script block after configuring the proxy. No render or UI changes are needed — only the fetch wrapper needs a real base URL and injected auth headers.
| Layer | Status | Required Action |
|---|---|---|
| Dashboard HTML / JS | ✓ Ready | All panels, KPIs, views, and interaction logic are fully implemented against the correct Backup API schema. |
| Proxy / Middleware | Not configured | Needs a reverse proxy or Node middleware that injects X-API-KEY and X-API-SECRET headers and forwards to your Datto partner hostname. |
| Datto Backup API | Not reachable | API must be enabled in the Datto partner portal under Integrations → API. Generate a public/private key pair there. |
| Auth (API Key) | Not configured | Datto Backup uses HTTP Basic with X-API-KEY and X-API-SECRET headers (not OAuth). No token expiry — keys are long-lived until revoked. |
| Restore Actions | Not available | No REST restore endpoint exists in the Datto Backup API. Restores must use the partner portal or Datto RMM agent commands. |
| Mock Function / Array | Produces | Replaces |
|---|---|---|
| ASSETS array | 58 asset objects matching the /bcdr/asset response schema with client, OS, backup state, storage, screenshot status | GET /bcdr/asset |
| APPLIANCES array | 7 appliance objects matching /bcdr/device response schema with model, storage, online state, last offsite | GET /bcdr/device |
| VOLUMES array | One volume per asset, matching /bcdr/asset/backupVolumes with local/offsite sizes and status | GET /bcdr/asset/backupVolumes |
| renderActivitySeed() | 10 activity log entries derived from asset backup events | Backup event log (no dedicated API endpoint) |
Architecture
Single self-contained HTML file. No build step, no npm dependencies. All logic runs in-browser. The proxy layer is the only external dependency needed for live data.
Datto Backup uses HTTP Basic authentication with two custom headers — not Bearer tokens. Keys are long-lived (no expiry by default) and must be stored securely in the proxy environment, never in the browser-side HTML.
Header Bar
52px bar across the top. Contains product identity, live status pills, and a UTC clock. The KTC home bar and HOME link have been removed per suite directive.
| Element | Content | Data Source |
|---|---|---|
| Brand icon | Cloud SVG, hexagonal clip-path | Static |
| Brand name | "DATTO BACKUP" — Orbitron, cyan accent | Static |
| Brand tag | "BCDR OPERATIONS CONSOLE" | Static |
| Pill: API status | "BCDR API v1 READY" | Static (switches to CONNECTED when proxy live) |
| Pill: failure count | N BACKUP FAILURES | Computed from assets.filter(a => !a.backedUp).length |
| Pill: mode | DEMO MODE / LIVE | Driven by DEMO_MODE constant |
| Clock | HH:MM:SS UTC | setInterval 1s, reads Date.getUTC*() |
KPI Strip
Six equal-width metric cards driven by updateKPIs(), which runs on every refreshAll() call.
| KPI | Calculation | API Source | Color |
|---|---|---|---|
| Protected Assets | assets.length | GET /bcdr/asset → totalCount | Cyan |
| Backups OK | assets.filter(a => a.backedUp).length | GET /bcdr/asset → backedUp=true | Green |
| Backup Failures | assets.filter(a => !a.backedUp).length | GET /bcdr/asset → backedUp=false | Red |
| Screenshot Fails | assets.filter(a => a.ssStatus==='failed').length | GET /bcdr/device/screenshots | Amber |
| Local Storage | sum(localUsedGb) / 1024 → TB | GET /bcdr/asset/backupVolumes → localUsedSize | Purple |
| Appliances | appliances.length | GET /bcdr/device → totalCount | Cyan |
Protected Asset Status Table
Main center panel on the dashboard. Lists all protected assets with their most recent backup state. Searchable and filterable.
renderAssetTable(). Applies applyAssetFilters() (text search + status filter) then slices to 50 rows. Clicking a row opens the asset modal.| Column | API Field | Display Logic |
|---|---|---|
| HOSTNAME | asset.hostname | Bold, white. Clickable — opens modal. |
| CLIENT | asset.client.name | Mono, muted, truncated to 18 chars. |
| TYPE | asset.operatingSystem | Abbreviated chip: "WServer 2022" → "WServer2022", "Windows 11 Pro" → "W11 Pro". |
| LAST BACKUP | asset.lastSuccessfulBackup (computed as hrs ago) | Green <8h, Amber 8–24h, Red >24h. |
| LOCAL | asset.localUsedGb → fmtBytes() | Formatted as GB or TB. |
| OFFSITE | asset.offsiteUsedGb → fmtBytes() | Muted color — secondary metric. |
| STATUS | asset.backedUp | Green "OK" badge or blinking red "FAILED" badge. |
| Filter | Logic |
|---|---|
| Search input | hostname.includes(q) || client.name.includes(q) — case-insensitive, fires on every keypress via oninput |
| Status dropdown: ALL | No filter applied |
| Status dropdown: OK | a.backedUp === true |
| Status dropdown: FAILED | a.backedUp === false |
| Status dropdown: WARNING | a.backedUp && a.ssStatus === 'pending' |
Alert Feed
Right column on the dashboard. Shows up to 10 active alerts derived from asset backup failures and screenshot verification failures.
!a.backedUp → Critical, a.ssStatus === 'failed' → Warning. This means alert state only updates when the 30-second refreshAll() poll completes.
renderAlertFeed(). First collects failed backup assets (red stripe), then adds screenshot failures for otherwise healthy assets (amber stripe). Limited to 10 items total.Storage Health Panel
Dashboard bottom-right. Summary view of local and offsite storage utilization across all backup volumes.
renderStorageSummary() from the volumes array. Shows: local TB used, avg utilisation progress bar, offsite TB, offsite replication percentage, and counts of OK vs warning volumes.Backup Activity Log
Dashboard bottom-left. Chronological log of backup events, API sync completions, and replication status messages.
renderActivitySeed() which derives entries from the asset state. In production this should be supplemented by a CW Manage or PSA ticket event feed if a timeline of backup actions is needed.
Screenshot Verification View
Sidebar nav → "Screenshots". Grid of all protected assets with their latest bootability verification result.
renderScreenshots(). Displays 30 assets in a 3-column card grid. Each card shows hostname, client, and screenshot status (PASSED ✅ / FAILED ❌ / PENDING ⏳). Card border color matches status. Click opens asset modal.GET /bcdr/device/screenshots endpoint returns the most recent screenshot result per asset only. Historical per-snapshot screenshot pass/fail data is only available in the Datto partner portal UI. There is no public bulk historical screenshot endpoint.
Failures View
Sidebar nav → "Failures". Full table of all assets with failed or overdue backups.
renderFailures(). Filters assets where !backedUp || hoursAgo > 24. Shows hostname, client, last success timestamp, inferred failure reason, hours missed, and action buttons (RETRY / DETAIL).The Datto Backup API does not return a structured failure reason string. In demo mode, failure reasons are randomly assigned from a pool of common causes. In production, failure reason text must be extracted from the Datto portal logs or from agent-level status fields where available on the individual GET /bcdr/asset/{serialNumber} response.
| Demo Reason | Real Source |
|---|---|
| Snapshot failed: VSS error | Check Datto agent logs on the asset |
| Agent offline | asset.pairingState !== 'paired' or lastSeenDate stale |
| Network unreachable | Agent last seen timestamp + network monitoring |
| Volume locked | Windows VSS status on the protected system |
| Insufficient storage | backupVolume.localUsedSize / localTotalSize > 0.95 |
Storage View
Sidebar nav → "Storage". Four summary KPIs and a full volume detail table.
renderStorage() from the volumes array. Table columns: asset name, client, local used, local total, local % (with progress bar), offsite used, status badge.| API Field | Type | Description |
|---|---|---|
| assetSerialNumber | string | Links volume to agent via GET /bcdr/asset/{sn} |
| assetName | string | Hostname of the backed-up asset |
| clientName | string | Client account name |
| localUsedSize | integer (GB) | Local backup storage used in gigabytes |
| localTotalSize | integer (GB) | Total local backup capacity in gigabytes |
| offsiteUsedSize | integer (GB) | Offsite (Datto Cloud) storage used |
| status | string | "ok" or "warning". Warning threshold set at >85% local utilisation in dashboard logic. |
Appliances View
Sidebar nav → "Appliances". Card grid of all BCDR appliances (SIRIS, ALTO, Cloud) with storage gauges and online status.
renderAppliances() from the appliances array. Each card shows: name, model, IP, serial, assets protected count, local/offsite storage, online status, and a local storage progress bar.| API Field | Type | Description |
|---|---|---|
| serialNumber | string | Unique appliance identifier |
| name | string | Friendly name set in the partner portal |
| model | string | Hardware model: SIRIS 5, SIRIS 4, ALTO 4+, ALTO 3, or Datto Cloud |
| internalIP | string | LAN IP address of the appliance |
| lastSeenDate | ISO timestamp | Last heartbeat from the appliance |
| localStorageUsed | integer (GB) | Used local storage on the appliance |
| localStorageAvailable | integer (GB) | Available local storage remaining |
| offsiteStorageUsed | integer (GB) | Offsite cloud storage used by this appliance |
| latestOffsite | ISO timestamp | Timestamp of the most recent successful offsite sync |
Asset Modal
Slide-in detail modal triggered by clicking any asset row or screenshot card. Shows full asset detail with action buttons.
| Field | API Source | Display Logic |
|---|---|---|
| Client | asset.client.name | Full client name |
| Operating System | asset.operatingSystem | Full OS string |
| Last Successful Backup | asset.lastSuccessfulBackup (hrs ago) | Green <8h, Red ≥8h |
| Screenshot Status | asset.ssStatus | Green PASSED, Red FAILED, Amber PENDING |
| Local Storage Used | asset.localUsedGb / localTotGb | "X GB / Y GB" format |
| Offsite Storage | asset.offsiteUsedGb | Formatted GB/TB |
| Ransomware Detection | asset.ransomwareDetectionEnabled | Green ENABLED, Amber DISABLED |
| Pairing State | asset.pairingState | Uppercase string |
| Failure reason | Inferred — no API field | Shown only when failureReason is set. Red alert block. |
All API Endpoints
Every Datto Backup REST endpoint used or referenced in this dashboard. Base URL: https://{partner}.dattobackup.com/api/v1
startBackup (force backup) and startScreenshot (trigger verification). Called by Force Backup and Check Screenshot buttons in asset modal.SimulatedstartBackup. Called by RETRY button in failures view.SimulatedransomwareDetectionEnabled. Called by the Enable Ransomware button in the asset modal (shown only when detection is off).Simulated| Requested Feature | Status | Workaround |
|---|---|---|
| Snapshot restore via REST | No endpoint | Restores must be initiated in the Datto partner portal UI only. |
| Backup event log / audit trail | No endpoint | Derive from lastSuccessfulBackup timestamps on the asset list. |
| Per-snapshot screenshot history | Latest only | /bcdr/device/screenshots returns the most recent result only. History requires portal access. |
| Alert/notification stream | No endpoint | Alerts are computed client-side from asset state. For push alerts, use Datto webhook integrations if available on the account. |
| CSAT / satisfaction data | No endpoint | Not applicable to Datto Backup. Use CW Manage or PSA for CSAT data. |
| Patch management | Wrong product | Patches are a Datto RMM concept. Not present in the Backup API. |
Config & Fields Reference
All configurable constants in the dashboard script block.
| Constant | Default | Effect |
|---|---|---|
| DATTO_BASE | Placeholder URL | Set to your partner hostname: https://{partner}.dattobackup.com/api/v1 |
| DEMO_MODE | true | Set to false when proxy is live. Switches all dattoFetch() calls from mock to real fetch. |
| startAutoRefresh(ms) | 30000ms | Poll interval. Lower to 15000ms for faster updates; increase to 60000ms to reduce API load. |
| CLIENTS array | 7 clients | Demo client roster. In production, derive from unique asset.client.name values. |
| ASSETS length | 58 assets | Demo asset count. In production, populated from GET /bcdr/asset response. |
| Storage warning threshold | 85% | In VOLUMES map and renderStorage(): localUsedSize / localTotalSize > 0.85 |
| Backup overdue threshold | 24h | In renderFailures(): assets with hoursAgo > 24 are flagged regardless of backedUp field. |
Documented Limitations
Known constraints of the current implementation and the Datto Backup API itself.
| ID | Limitation | Root Cause | Resolution |
|---|---|---|---|
| L-01 | All data is simulated | DEMO_MODE = true. Proxy not configured. | Set DEMO_MODE = false after proxy setup. See §19. |
| L-02 | No backup event log endpoint | Datto Backup API has no audit trail or event log resource. | Derive from lastSuccessfulBackup timestamps. Supplement with PSA ticket events. |
| L-03 | Screenshot history is latest-only | GET /bcdr/device/screenshots returns only the most recent result per asset. | Link to Datto partner portal for historical screenshot review. |
| L-04 | Failure reasons are inferred, not returned | Datto Backup API does not include a structured failureReason field on asset objects. | Parse agent logs via RMM or portal. Map from pairingState and storage fields. |
| L-05 | Restore cannot be triggered via API | No REST restore endpoint exists in the Datto Backup public API. | Restores must use the partner portal or be scripted via Datto RMM agent commands. |
| L-06 | Alert state not persisted | No alert acknowledgment endpoint. Resolved state is in-memory only. | Use PSA ticket creation as the durable acknowledgment record. |
| L-07 | Bulk action not natively supported | POST /bcdr/asset/{sn}/actions is per-asset. "Force Backup All" must iterate in a loop. | Client-side iteration with Promise.allSettled() in the fetch wrapper. |
| L-08 | No RBAC on dashboard buttons | Static HTML — any user who loads the file sees all buttons including Retry and Enable Ransomware. | Enforce at proxy layer: restrict write endpoints by authenticated role. |
Proxy Activation Checklist
Step-by-step to move from demo mode to live Datto Backup API data.
GET https://{partner}.dattobackup.com/api/v1/bcdr/asset with headers X-API-KEY and X-API-SECRET. A 200 response with an asset array confirms credentials are valid.X-API-KEY and X-API-SECRET headers from environment variables, (b) forward requests to the Datto base URL, (c) add Access-Control-Allow-Origin for the dashboard's domain. Options: nginx, Node/Express, or Cloudflare Worker.const DATTO_BASE = 'https://your-proxy.example.com/api/v1' and const DEMO_MODE = false. Uncomment the real fetch block inside dattoFetch()./bcdr/asset request should return HTTP 200 with a real asset array. The KPI "Protected Assets" count should match your actual BCDR agent count in the portal.backedUp, lastSuccessfulBackup, client.name, etc.). If the real API response uses different casing or nesting, add a normalizer function between dattoFetch() and the render functions.POST /bcdr/asset/{sn}/actions against a non-critical test agent to confirm the action fires correctly and the asset shows updated state on next poll.- API keys generated in Datto partner portal (Integrations → API)
- Partner hostname confirmed — base URL validated via curl/Postman
- Proxy deployed with X-API-KEY and X-API-SECRET injected from environment
- CORS headers configured for dashboard origin
- DATTO_BASE updated and DEMO_MODE set to false in script block
- Real fetch block uncommented inside dattoFetch()
- GET /bcdr/asset returns real assets — confirmed in DevTools Network tab
- KPI count matches agent count in Datto partner portal
- Screenshot view shows real pass/fail states from GET /bcdr/device/screenshots
- Storage view shows real GB values from GET /bcdr/asset/backupVolumes
- Write endpoints tested on non-critical agent before production enable
- RBAC enforced at proxy layer — write endpoints restricted by role
Troubleshooting
Common issues during deployment and daily operation. Open DevTools Console and Network tabs before anything else.
Access-Control-Allow-Origin: https://your-dashboard-domain (or * for development) to every proxied response. If using nginx: add_header 'Access-Control-Allow-Origin' '$http_origin';. Do not attempt to call the Datto API directly from the browser — you cannot add the auth headers from a browser context without exposing the private key.asset.backedUp, asset.client.name, asset.lastSuccessfulBackup etc. If the real API response uses different names (some Datto API versions return camelCase differently), add a normalization function that maps the real field names to the dashboard's expected schema before passing the data to render functions.ssStatus mapping in the normalization layer. Also note that newly paired agents may genuinely show PENDING if no screenshot verification has completed yet.dattoFetch('/bcdr/asset/' + serial + '/actions', ...) call with body { "action": "startBackup" }. Verify the action type string against current Datto API documentation — it may vary by account configuration.hidden: true. Add a filter for !a.hidden in loadDashboard() if needed.