Webflow Integration
Load DBindly collection data into your Webflow pages
Overview
DBindly integrates seamlessly with Webflow, allowing you to load dynamic collection data into your pages without any backend setup. You can display product catalogs, blog posts, team directories, or any other data stored in your DBindly collections.
There are three approaches to loading data in Webflow:
- DBindly Script (Recommended) - Use data attributes for automatic binding
- Vanilla JavaScript - Direct API calls for full control
- DBindly SDK - Enhanced features with caching and retries
Prerequisites
Before starting, you'll need:
- A DBindly account with at least one collection
- Your API key from the DBindly dashboard
- A Webflow project with Editor or higher plan (for custom code)
Option 1: DBindly Script (Recommended)
The easiest way to load data is using the DBindly script with data attributes.
Step 1: Add the Script
Go to Project Settings then Custom Code then Head Code and add:
<script src="https://api.dbindly.com/dbindly.min.js"></script>
<script>
DBindly.init({
apiUrl: 'https://api.dbindly.com',
apiKey: 'pk_live_your_api_key',
cache: true,
debug: false
});
</script>Step 2: Add Data Attributes to Elements
In Webflow Designer, add custom attributes to your elements:
For single data items (using data ID from URL):
<div dbind_load="{{dataId}}">
<h1 dbind_data="title"></h1>
<p dbind_data="description"></p>
<img dbind_src="image" dbind_alt="title">
</div>For collection lists:
<div dbind_collection="products" dbind_limit="12">
<div dbind_template>
<h3 dbind_data="name"></h3>
<p dbind_data="price" dbind_format="currency"></p>
<a dbind_href="link">View Product</a>
</div>
</div>See Data Attributes for the complete attribute reference.
Option 2: Vanilla JavaScript
For more control, use direct API calls in your Webflow custom code.
Fetching Collection Data
Add this to Page Settings then Custom Code then Before body tag:
<script>
(async function() {
const API_URL = 'https://api.dbindly.com';
const COLLECTION_SLUG = 'your-collection-slug';
try {
const response = await fetch(
`${API_URL}/public/collections/${COLLECTION_SLUG}/data?limit=20&page=1`
);
const result = await response.json();
// result.data = array of items
// result.pagination = { page, limit, total, totalPages, hasMore }
const container = document.querySelector('[data-products]');
result.data.forEach(item => {
const card = document.createElement('div');
card.className = 'product-card';
card.innerHTML = `
<img src="${item.data.image}" alt="${item.data.name}">
<h3>${item.data.name}</h3>
<p class="price">$${item.data.price}</p>
`;
container.appendChild(card);
});
} catch (error) {
console.error('Failed to load data:', error);
}
})();
</script>Fetching a Single Item
<script>
(async function() {
const API_URL = 'https://api.dbindly.com';
// Get data ID from URL parameter
const params = new URLSearchParams(window.location.search);
const dataId = params.get('id');
if (!dataId) return;
try {
const response = await fetch(`${API_URL}/public/data/${dataId}`);
const item = await response.json();
// Populate your Webflow elements
document.querySelector('[data-title]').textContent = item.data.title;
document.querySelector('[data-description]').textContent = item.data.description;
document.querySelector('[data-image]').src = item.data.image;
} catch (error) {
console.error('Failed to load item:', error);
}
})();
</script>Batch Fetching Multiple Items
<script>
(async function() {
const API_URL = 'https://api.dbindly.com';
const IDS = ['product-001', 'product-002', 'product-003'];
try {
const response = await fetch(`${API_URL}/public/batch`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
dataIds: IDS,
fields: ['name', 'price', 'image'] // Optional: specific fields only
})
});
const result = await response.json();
// result.data = array of matching items
// result.count = number of items returned
console.log(result.data);
} catch (error) {
console.error('Failed to batch fetch:', error);
}
})();
</script>Option 3: DBindly SDK
If the SDK is published to a CDN, you can use it for built-in caching and retry logic:
<script type="module">
import { createDBindlyClient } from 'https://cdn.jsdelivr.net/npm/@dbindly/sdk';
const client = createDBindlyClient({
apiUrl: 'https://api.dbindly.com',
apiKey: 'pk_live_your_api_key',
cache: true,
cacheTTL: 300000, // 5 minutes
retryAttempts: 3
});
// Fetch collection with pagination
const products = await client.fetchCollection('products', {
page: 1,
limit: 20,
sort: 'price',
order: 'asc'
});
// Fetch single item
const product = await client.fetchData('product-123');
// Batch fetch
const items = await client.fetchBatch(['id1', 'id2', 'id3']);
</script>API Reference
Collection Endpoint
GET /api/public/collections/{slug}/data
| Parameter | Type | Default | Description |
|---|---|---|---|
| page | number | 1 | Page number |
| limit | number | 20 | Items per page (1-100) |
| sort | string | createdAt | Field to sort by |
| order | string | desc | Sort order (asc/desc) |
Single Item Endpoint
GET /api/public/data/{dataId}
Batch Endpoint
POST /api/public/batch
Body:
{
"dataIds": ["id1", "id2"],
"fields": ["name", "price"]
}Practical Examples
Dynamic Product Grid
In Webflow, create a container div with the attribute data-products:
<script>
(async function() {
const container = document.querySelector('[data-products]');
if (!container) return;
// Show loading state
container.innerHTML = '<p class="loading">Loading products...</p>';
try {
const response = await fetch(
'https://api.dbindly.com/public/collections/products/data?limit=12'
);
const { data } = await response.json();
container.innerHTML = data.map(product => `
<div class="product-card">
<img src="${product.data.image}" alt="${product.data.name}" loading="lazy">
<h3>${product.data.name}</h3>
<p class="price">$${product.data.price.toFixed(2)}</p>
<a href="/product?id=${product.dataId}" class="btn">View Details</a>
</div>
`).join('');
} catch (error) {
container.innerHTML = '<p class="error">Failed to load products. Please refresh.</p>';
}
})();
</script>Blog Posts with Pagination
<script>
let currentPage = 1;
const limit = 6;
async function loadPosts(page) {
const container = document.querySelector('[data-posts]');
const pagination = document.querySelector('[data-pagination]');
try {
const response = await fetch(
`https://api.dbindly.com/public/collections/blog-posts/data?page=${page}&limit=${limit}&sort=publishedAt&order=desc`
);
const result = await response.json();
container.innerHTML = result.data.map(post => `
<article class="post-card">
<img src="${post.data.image}" alt="${post.data.title}">
<h2>${post.data.title}</h2>
<p>${post.data.excerpt}</p>
<a href="/blog/${post.dataId}">Read More</a>
</article>
`).join('');
// Update pagination
pagination.innerHTML = `
<button onclick="loadPosts(${page - 1})" ${page <= 1 ? 'disabled' : ''}>Previous</button>
<span>Page ${page} of ${result.pagination.totalPages}</span>
<button onclick="loadPosts(${page + 1})" ${!result.pagination.hasMore ? 'disabled' : ''}>Next</button>
`;
currentPage = page;
} catch (error) {
container.innerHTML = '<p>Failed to load posts.</p>';
}
}
loadPosts(1);
</script>Tips and Best Practices
1. Add Loading States
Always show a loading indicator while data is being fetched:
container.innerHTML = '<div class="skeleton-loader"></div>';2. Handle Errors Gracefully
Display user-friendly error messages:
catch (error) {
container.innerHTML = `
<p class="error">Unable to load content.
<button onclick="location.reload()">Try Again</button></p>
`;
}3. Use Lazy Loading for Images
Add loading lazy to images below the fold:
<img src="${item.image}" loading="lazy" alt="${item.name}">4. Cache Data in Session Storage
For repeated page visits:
const cacheKey = `dbindly_${collectionSlug}_${page}`;
const cached = sessionStorage.getItem(cacheKey);
if (cached) {
renderData(JSON.parse(cached));
} else {
const data = await fetchData();
sessionStorage.setItem(cacheKey, JSON.stringify(data));
renderData(data);
}5. Use URL Parameters for Dynamic Pages
Pass data IDs through URL parameters for detail pages:
// On list page
<a href="/product?id=${product.dataId}">View</a>
// On detail page
const dataId = new URLSearchParams(location.search).get('id');Troubleshooting
CORS Errors
DBindly public endpoints allow requests from any origin. If you see CORS errors:
- Ensure you are using the correct endpoint (/api/public/...)
- Check that your API key is valid
Data Not Loading
- Verify your collection slug matches exactly
- Check browser console for error messages
- Ensure your API key has the correct permissions
Slow Loading
- Reduce the limit parameter
- Enable caching in DBindly.init()
- Use pagination instead of loading all data at once
Next Steps
- API Endpoints - Full API reference
- Data Attributes - Complete attribute documentation
- API Keys - Managing API key permissions