# Widgets API
# API Endpoints
| Endpoint | Method | Auth | Description |
|---|---|---|---|
/api/widgets/ | GET | Public | List all widgets |
/api/widgets/{uuid} | GET | Public | Get single widget |
/api/widgets/{uuid} | POST | Admin | Create/update widget |
/api/widgets/{uuid} | DELETE | Admin | Delete widget |
/api/widgets/delete/{uuid} | POST | Admin | Delete widget (alias) |
/api/widgets/attach_to_study | POST | Admin | Attach widget to study |
/api/widgets/detach_study | POST | Admin | Detach widget from study |
/api/widgets/by_dataset/{idno} | GET | Public | Get widgets by dataset |
# 1. List All Widgets
Endpoint: GET /api/widgets/
Authentication: Public (no authentication required)
Example Request:
curl -X GET "https://your-catalog-url.com/api/widgets/" \
-H "Accept: application/json"
Example Response:
{
"total": 3,
"records": [
{
"id": 1,
"uuid": "abc123-def456-ghi789",
"title": "Sample Line Chart",
"description": "A basic line chart visualization",
"thumbnail": "thumbnail.png",
"thumbnail_url": "https://your-catalog-url.com/files/embed/.../thumbnail.png",
"storage_path": "5d41402abc4b2a76b9719d911017c592",
"published": 1,
"changed": "1704067200",
"created": "1703980800",
"link": "https://your-catalog-url.com/widgets/view/abc123-def456-ghi789"
}
]
}

# 2. Get Single Widget
Endpoint: GET /api/widgets/{uuid}
Authentication: Public
Example Request:
curl -X GET "https://your-catalog-url.com/api/widgets/abc123-def456-ghi789" \
-H "Accept: application/json"
Example Response:
{
"record": {
"id": 1,
"uuid": "abc123-def456-ghi789",
"title": "Sample Line Chart",
"description": "A basic line chart visualization",
"thumbnail": "thumbnail.png",
"storage_path": "5d41402abc4b2a76b9719d911017c592",
"published": 1,
"created": "1703980800",
"changed": "1704067200",
"full_path": "files/embed/5d41402abc4b2a76b9719d911017c592",
"link": "https://your-catalog-url.com/widgets/view/abc123-def456-ghi789",
"related_studies": [
{
"sid": 123,
"idno": "STUDY-001",
"link": "https://your-catalog-url.com/catalog/123"
}
]
}
}
# 3. Create Widget
Endpoint: POST /api/widgets/{uuid}
Authentication: Admin required
Parameters:
uuid(path parameter): Unique identifier for the widget (alphanumeric and dashes only, max 100 characters)title(form data): Widget title (required, max 255 characters)description(form data): Widget description (optional, max 500 characters)thumbnail(form data): Thumbnail filename (optional, max 200 characters)file(form data): ZIP file containing widget files (required)overwrite(form data): Set to "yes" to overwrite existing widget (optional)
Example Request using cURL:
curl -X POST "https://your-catalog-url.com/api/widgets/my-widget-uuid-001" \
-H "X-API-KEY: your-api-key" \
-H "Accept: application/json" \
-F "title=My Line Chart Widget" \
-F "description=An interactive line chart showing data trends" \
-F "thumbnail=thumbnail.png" \
-F "file=@/path/to/my-widget.zip" \
-F "overwrite=yes"
Example Response:
{
"status": "success",
"options": {
"title": "My Line Chart Widget",
"description": "An interactive line chart showing data trends",
"thumbnail": "thumbnail.png",
"uuid": "my-widget-uuid-001"
},
"result": {
"folder": "5d41402abc4b2a76b9719d911017c592",
"uuid": "my-widget-uuid-001",
"link": "https://your-catalog-url.com/widgets/view/my-widget-uuid-001"
}
}
Error Response:
{
"status": "error",
"message": "VALIDATION_ERROR: The Title field is required."
}

# 4. Update Widget
Endpoint: POST /api/widgets/{uuid} (same as create)
Authentication: Admin required
Updating a widget uses the same endpoint as creating. If a widget with the specified UUID already exists, it will be updated. Include overwrite=yes in your request.
Example Request:
curl -X POST "https://your-catalog-url.com/api/widgets/my-widget-uuid-001" \
-H "X-API-KEY: your-api-key" \
-H "Accept: application/json" \
-F "title=Updated Widget Title" \
-F "description=Updated description" \
-F "file=@/path/to/updated-widget.zip" \
-F "overwrite=yes"
# 5. Delete Widget
Endpoint: DELETE /api/widgets/{uuid} or POST /api/widgets/delete/{uuid}
Authentication: Admin required
Example Request (DELETE):
curl -X DELETE "https://your-catalog-url.com/api/widgets/my-widget-uuid-001" \
-H "X-API-KEY: your-api-key" \
-H "Accept: application/json"
Example Request (POST alias):
curl -X POST "https://your-catalog-url.com/api/widgets/delete/my-widget-uuid-001" \
-H "X-API-KEY: your-api-key" \
-H "Accept: application/json"
Example Response:
{
"status": "success"
}
Error Response:
{
"status": "error",
"message": "RECORD_NOT_FOUND"
}

# 6. Get Widgets by Dataset
Endpoint: GET /api/widgets/by_dataset/{idno}
Authentication: Public
Parameters:
idno(path parameter): Study/dataset identifier or IDNO
Query Parameters:
id_format(optional): Set to "id" if passing study ID instead of IDNO
Example Request:
curl -X GET "https://your-catalog-url.com/api/widgets/by_dataset/STUDY-001" \
-H "Accept: application/json"
Example Request with Study ID:
curl -X GET "https://your-catalog-url.com/api/widgets/by_dataset/123?id_format=id" \
-H "Accept: application/json"
Example Response:
{
"record": [
{
"id": 1,
"uuid": "abc123-def456-ghi789",
"title": "Sample Line Chart",
"description": "A basic line chart visualization",
"link": "https://your-catalog-url.com/widgets/view/abc123-def456-ghi789"
}
]
}
# Previewing Widgets
# Web Interface Preview
You can preview widgets through the web interface at:
Widget Info Page:
https://your-catalog-url.com/widgets/view/{uuid}
This page displays widget information, metadata, and related studies.

Embed Preview:
https://your-catalog-url.com/widgets/embed/{uuid}
This page shows the widget as it would appear when embedded, with responsive iframe support via pym.js.

Widgets List:
https://your-catalog-url.com/widgets/
Browse all available widgets in the catalog.

# Attaching Widgets to Studies
Widgets can be attached to studies, making them appear on study pages.
# Attach Widget to Study
Endpoint: POST /api/widgets/attach_to_study
Authentication: Admin required
Request Body (JSON):
{
"uuid": "abc123-def456-ghi789",
"idno": "STUDY-001"
}
Example Request:
curl -X POST "https://your-catalog-url.com/api/widgets/attach_to_study" \
-H "X-API-KEY: your-api-key" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"uuid": "abc123-def456-ghi789",
"idno": "STUDY-001"
}'
Example Response:
{
"status": "success",
"options": {
"uuid": "abc123-def456-ghi789",
"idno": "STUDY-001"
},
"result": true
}
# Detach Widget from Study
Endpoint: POST /api/widgets/detach_study
Authentication: Admin required
Request Body (JSON):
{
"uuid": "abc123-def456-ghi789",
"idno": "STUDY-001"
}
Example Request:
curl -X POST "https://your-catalog-url.com/api/widgets/detach_study" \
-H "X-API-KEY: your-api-key" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"uuid": "abc123-def456-ghi789",
"idno": "STUDY-001"
}'
Example Response:
{
"status": "success",
"options": {
"uuid": "abc123-def456-ghi789",
"idno": "STUDY-001"
},
"result": true
}

# Managing Widgets
# Widget Metadata
Each widget has the following metadata fields:
- UUID: Unique identifier (alphanumeric and dashes, max 100 chars)
- Title: Widget title (required, max 255 chars)
- Description: Widget description (optional, max 500 chars)
- Thumbnail: Thumbnail image filename (optional, max 200 chars)
- Storage Path: Auto-generated MD5 hash of UUID
- Published: Publication status (0 or 1)
- Created: Creation timestamp (Unix timestamp)
- Changed: Last modification timestamp (Unix timestamp)
- Related Studies: List of studies the widget is attached to
# Widget Lifecycle
- Create: Upload widget ZIP file via API
- Update: Re-upload with same UUID (use
overwrite=yes) - Attach: Link widget to one or more studies
- Preview: View widget in web interface
- Delete: Remove widget and all associations
# Best Practices
- UUID Naming: Use descriptive, unique UUIDs (e.g.,
line-chart-population-2024) - File Organization: Keep widget files organized in subfolders if needed
- Responsive Design: Ensure widgets work on mobile and desktop
- Performance: Optimize images and minimize JavaScript bundle size
- Testing: Test widgets locally before uploading
- Height: Always use fixed pixel heights (e.g.,
500px) instead of percentage heights
# Advanced Features
# Responsive Iframe Embedding
Widgets are automatically enhanced with pym.js for responsive iframe embedding. The embed endpoint automatically injects:
<script type="text/javascript" src="https://pym.nprapps.org/pym.v1.min.js"></script>
<script>window.onload = function () {var pymChild = new pym.Child();}</script>
This ensures widgets automatically resize to fit their container.
# External Libraries
You can use external CDN libraries in your widgets. Common libraries include:
- ECharts:
https://cdn.jsdelivr.net/npm/echarts@5.4.3/dist/echarts.min.js - D3.js:
https://d3js.org/d3.v7.min.js - Chart.js:
https://cdn.jsdelivr.net/npm/chart.js - jQuery:
https://code.jquery.com/jquery-3.6.0.min.js - Bootstrap 5:
https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css
# Dependencies and Version Compatibility
Important Dependency Changes:
- Versions prior to 5.5.1: jQuery and Bootstrap 4 or 5 are required and you must include them in your widget.
- Version 5.5.1 and later: These dependencies are removed from the widget environment.
Including Dependencies:
You can include dependencies in two ways:
- Via CDN (recommended for most cases):
<!-- jQuery -->
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<!-- Bootstrap 5 CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
- Bundled in ZIP file (for offline use or version control):
- Download jQuery and Bootstrap files
- Include them in your widget ZIP file
- Reference them with relative paths in your HTML
Height Requirements:
Widgets must use fixed pixel heights (e.g., 500px, 400px) instead of percentage heights (e.g., 100%, 100vh). Percentage heights will cause the widget to not render correctly in the embedded iframe.
Correct:
<div id="chart-container" style="width: 100%; height: 500px;"></div>
Incorrect:
<div id="chart-container" style="width: 100%; height: 100%;"></div>
# Data Fetching
For your widgets, you can use APIs to fetch data using javascript.
// Fetch data via API
fetch('https://example.com/api/data')
.then(response => response.json())
.then(data => {
// Process and display data
});
# Thumbnail Images
Include a thumbnail image in your widget ZIP file and reference it in the thumbnail field when creating the widget. The thumbnail will be displayed in widget listings.
# Troubleshooting
# Common Issues
# 1. "ZIP does not contain an HTML file"
Problem: Your ZIP file doesn't contain any HTML files.
Solution: Ensure your ZIP contains at least one .html file. The system will automatically rename the first HTML file to index.html if needed.
# 2. "VALIDATION_ERROR: The Title field is required"
Problem: Missing required field when creating widget.
Solution: Ensure you include the title field in your API request. All required fields:
title(required)uuid(required, in URL path)file(required, ZIP file)
# 3. Widget not displaying correctly
Problem: Widget appears broken or doesn't load.
Solutions:
- Check browser console for JavaScript errors
- Verify all external CDN links are accessible
- Ensure file paths are relative (not absolute)
- Check that
index.htmlexists and is valid HTML - include jQuery and Bootstrap: Ensure you've included them in your widget (required for version 5.5 or earlier)
- If widget height is 0 or not visible: Check that you're using fixed pixel heights (e.g.,
500px) instead of percentage heights (e.g.,100%)
# 3a. Widget height is zero or not rendering
Problem: Widget container has no height or doesn't display.
Cause: Using percentage-based heights (e.g., height: 100%, height: 100vh) which don't work correctly in embedded iframes.
Solution: Always use fixed pixel heights:
<!-- Correct -->
<div id="chart-container" style="width: 100%; height: 500px;"></div>
<!-- Incorrect -->
<div id="chart-container" style="width: 100%; height: 100%;"></div>
Also ensure parent containers have fixed heights if needed:
/* Correct */
.container {
height: 500px;
}
/* Incorrect */
.container {
height: 100%;
}
# 4. "ACCESS-DENIED" error
Problem: Insufficient permissions for API operation.
Solution: Ensure you have admin privileges and a valid API key. Check that your API key is included in the request headers.
# 5. File upload fails
Problem: ZIP file upload returns error.
Solutions:
- Verify ZIP file contains only allowed file types (html, js, css, png, jpg, gif, ttf, json)
- Check file size limits
- Ensure ZIP file is not corrupted
- Verify the
filefield name in form data is correct
# 6. Widget not appearing on study page
Problem: Widget is created but doesn't show on study page.
Solutions:
- Verify widget is attached to the study using
attach_to_studyendpoint - Check that the study IDNO is correct
- Verify widget is published (published = 1)
- Check study page template includes widget display code
# Examples
# Complete Example: Creating a Widget
# 1. Create widget files (index.html, style.css, script.js)
# 2. Package into ZIP file
zip -r my-widget.zip index.html style.css script.js
# 3. Create widget via API
curl -X POST "https://your-catalog-url.com/api/widgets/my-widget-001" \
-H "X-API-KEY: your-api-key" \
-F "title=My First Widget" \
-F "description=An example widget" \
-F "file=@my-widget.zip"
# 4. Attach to study
curl -X POST "https://your-catalog-url.com/api/widgets/attach_to_study" \
-H "X-API-KEY: your-api-key" \
-H "Content-Type: application/json" \
-d '{"uuid": "my-widget-001", "idno": "STUDY-001"}'
# 5. Preview widget
# Visit: https://your-catalog-url.com/widgets/view/my-widget-001
For more information about the widget API, see the API documentation include with NADA by visiting the URL - https://your-nada-catalog/api-documentation/api-documentation/catalog-admin/#operation/createWidget (opens new window).
← Widgets Extend Login →