Skip to main content
RapidDev - Software Development Agency
weweb-tutorial

WeWeb Dynamic Pages: URL Parameters, Routing, and CMS Content

WeWeb dynamic pages use URL path parameters (e.g., /products/:id) to create data-driven routes — each URL maps to a different database record. Set up a collection that filters by the URL parameter, bind page elements to the fetched data, and your single page template renders any record from your database. This tutorial covers routing setup, data binding, query strings, and SEO limitations.

What you'll learn

  • How to create dynamic collection pages in WeWeb with URL path parameters like /products/:id
  • How to set up a collection that fetches a single record based on the current URL parameter
  • How to bind page elements to dynamically fetched data using WeWeb's binding system
  • How to use Query variables for URL query string parameters (e.g., ?tab=details)
  • The SEO limitations of WeWeb dynamic pages and practical workarounds
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Intermediate11 min read40–60 minWeWeb Free plan and above (backend data source required)March 2026RapidDev Engineering Team
TL;DR

WeWeb dynamic pages use URL path parameters (e.g., /products/:id) to create data-driven routes — each URL maps to a different database record. Set up a collection that filters by the URL parameter, bind page elements to the fetched data, and your single page template renders any record from your database. This tutorial covers routing setup, data binding, query strings, and SEO limitations.

Data-Driven Routing with WeWeb Dynamic Pages

Dynamic pages in WeWeb let a single page template render different content based on the URL. Instead of building a separate page for every product, article, or user profile, you create one page with a dynamic path like /products/:id. When a visitor hits /products/42, WeWeb reads the '42' from the URL, passes it to your data collection as a filter, fetches the matching record from your database, and populates the page elements with that record's data. This tutorial walks through creating a dynamic route, configuring the collection to filter by URL parameter, binding all the page elements, and handling edge cases like loading states and 404 scenarios. It also addresses the SEO challenge inherent to WeWeb's SPA architecture and the available workarounds.

Prerequisites

  • A WeWeb project with a backend data source connected (Supabase, Xano, REST API, or similar)
  • A database table or API endpoint with multiple records you want to display
  • A list page already built (or planned) that will link to the dynamic detail page
  • Basic familiarity with WeWeb collections and variable bindings

Step-by-step guide

1

Create a dynamic page with a URL path parameter

In the left panel, click the Pages icon → click + New page. Give the page a name like 'Product Detail'. In the Page settings panel (right sidebar) → URL path field, type the path with a parameter segment: /products/:id. The colon prefix marks 'id' as a dynamic segment — WeWeb will extract whatever appears in that URL position as the value of the path parameter 'id'. Save the page. Now WeWeb automatically creates a Path variable in the page's Data panel named 'id' (matching the parameter name you used). If you named it ':slug', the variable would be named 'slug'. You can name the parameter anything — just be consistent. Check Data panel → Variables → path parameters section to confirm the variable was created. This variable's value is automatically set to whatever appears in the URL when the page loads.

Expected result: A new page exists at /products/:id. In the Data panel → Variables, a path parameter variable named 'id' is automatically available.

2

Create a collection that filters by URL parameter

With your dynamic page open, go to the Data panel → Collections → + New collection → select your data source (e.g., Supabase). Configure the collection to fetch a single record matching the URL parameter. For Supabase: select your table (e.g., 'products'), then in the collection configuration set a filter: id equals [plug icon] → select path variables → id. This tells WeWeb to fetch only the product whose id matches the URL parameter. Name this collection 'currentProduct'. Under Fetch mode, select 'Fetched on page load' so data is available immediately. In the Filters section of the collection, check 'Ignore if empty' — this prevents the collection from running before the path variable resolves. After saving, the collection exposes: currentProduct.data (array with the matched record), currentProduct.isFetching (loading boolean), and currentProduct.isFetched. Since you filtered for a single record, the data array will have one item: currentProduct.data[0].

Expected result: The collection fetches the record matching the current URL parameter. In the WeWeb editor, you can preview the collection and see sample data returned.

3

Handle loading and empty states

Dynamic pages need to handle three states: loading (collection is fetching), data found (collection returned a record), and not found (no record matched). First, add a loading skeleton: drag a Skeleton Loader element onto the canvas. Select it → Settings → Conditional Rendering → bind to: currentProduct.isFetching. This shows the skeleton while data loads. Second, add a 'not found' section: create a Container with a '404 - Product not found' message. Bind its Conditional Rendering to: `currentProduct.isFetched && currentProduct.data.length === 0`. This appears only after the collection has finished fetching and returned empty results. Third, wrap all your main page content in a Container and bind its Conditional Rendering to: `currentProduct.isFetched && currentProduct.data.length > 0`. This ensures the real content only renders when data is available. This three-state approach prevents blank screens and confusing flashes of content.

Expected result: The page shows a skeleton loader while fetching, a 404 message when no record is found, and the populated content when data is successfully loaded.

4

Bind page elements to the fetched record

With your content Container visible and the collection returning data, bind each page element to the corresponding field from currentProduct.data[0]. Select a heading element → click the plug icon (🔌) next to the text property in the Settings panel → formula editor opens → type: currentProduct.data[0].name (replace 'name' with your actual field name). Repeat for description, price, image, and any other fields. For the product image: select an Image element → plug icon next to the Source property → currentProduct.data[0].image_url. For a price formatted with currency: `'$' + currentProduct.data[0].price.toFixed(2)`. For a rich text field: use the Rich Text element and bind its content property to currentProduct.data[0].description. For dates: use the date formula functions to format `currentProduct.data[0].created_at`. Every element on the page can be bound this way — buttons, tags, status indicators — using formulas that reference the fetched record.

typescript
1// Injection point: binding formula in WeWeb formula editor
2// Access nested object fields:
3currentProduct.data[0].attributes.color
4
5// Conditional value with fallback:
6currentProduct.data[0].sale_price || currentProduct.data[0].price
7
8// Format date:
9format(parseISO(currentProduct.data[0].created_at), 'MMMM d, yyyy')
10
11// Concatenate fields:
12currentProduct.data[0].first_name + ' ' + currentProduct.data[0].last_name
13
14// Check boolean field:
15currentProduct.data[0].in_stock ? 'In Stock' : 'Out of Stock'
16
17// Array field rendered as comma-separated string:
18currentProduct.data[0].tags.join(', ')

Expected result: All page elements display data from the fetched record. The page renders the correct product when you test with different URL parameters.

5

Link to your dynamic page from a list page

Dynamic pages are only useful when something links to them. On your list page (e.g., /products), create a collection that fetches all products. In a Flexbox Container, bind the Repeat items property to your products collection's data array. Inside the repeated container, add a button or text link. Add a workflow to it: On click → Navigate → Dynamic page → select 'Product Detail' → in the path parameter mapping, bind 'id' to `item.id` (the current repeated item's ID). This generates the correct URL for each product. Alternatively, if you want the entire card to be clickable rather than just a button, add the workflow to the outer repeated container. Now when users click a product card, they navigate to /products/42 (or whatever that product's ID is), and the dynamic page loads the correct record.

Expected result: Clicking a product in the list page navigates to the correct dynamic page URL, and the detail page displays that product's data.

6

Use Query variables for URL query string parameters

In addition to path parameters (/products/:id), WeWeb supports Query variables for URL query strings (e.g., /products?tab=reviews&sort=recent). Query variables are available automatically for any page — go to Data panel → Variables → scroll to the Query variables section. Any query string key becomes an accessible variable. For example, if the URL is /products/42?tab=reviews, you can access the tab variable in formulas. Use case: tab navigation where each tab changes the URL query string for shareability. Create a Tabs component → bind the active tab to a Query variable named 'tab'. Add a workflow: On tab change → Change Query variable 'tab' → to the selected tab name. Now the URL updates when tabs switch and refreshing the page restores the correct tab. For search pages: bind a collection filter to a Query variable 'q' and update it when the search input changes.

Expected result: URL query string parameters drive UI state (tab selection, filters, sort order) and persist across page refreshes.

7

Understand and work around SEO limitations

WeWeb generates a Vue.js SPA with no server-side rendering (SSR). This means dynamic pages (/products/42) serve the same empty HTML shell to every URL — the actual content is injected by JavaScript after page load. Search engine crawlers (Googlebot) can eventually index JS-rendered content, but with delays. Social media crawlers (Facebook, Twitter/X, LinkedIn) typically cannot render JavaScript and will not see dynamic meta tags for Open Graph sharing. To set per-page meta tags for dynamic pages: go to Page settings → SEO & Meta Tags → bind Title Tag to `currentProduct.data[0].name + ' | Your Store'` and bind Meta Description to `currentProduct.data[0].description.substring(0, 155)`. This works for Google (with delay) but not for social sharing. For social sharing and reliable SEO: consider using Prerender.io ($9–99/mo) to serve pre-rendered HTML to crawlers, or host dynamic content pages on a separate SSR platform (Next.js, Nuxt.js) while keeping your WeWeb app for authenticated sections.

Expected result: Dynamic page meta tags are bound to collection data. You understand the SPA SEO tradeoff and have a strategy for crawlers.

Complete working example

dynamic-page-collection-filter.json
1// This represents the collection configuration for a dynamic product page
2// Set this up in WeWeb: Data panel → Collections → + New → Supabase
3//
4// Collection name: currentProduct
5// Table: products
6// Fetch mode: On page load
7//
8// Filter configuration (set in the Filters section of the collection):
9{
10 "filters": [
11 {
12 "field": "id",
13 "operator": "eq",
14 "value": "{{path.id}}",
15 "ignoreIfEmpty": true
16 }
17 ],
18 "limit": 1
19}
20//
21// For REST API collection, the URL would be constructed as:
22// https://api.example.com/products/{{path.id}}
23//
24// Bindings to use in page elements:
25// Product name: currentProduct.data[0].name
26// Product price: '$' + currentProduct.data[0].price.toFixed(2)
27// Product image: currentProduct.data[0].image_url
28// Product description: currentProduct.data[0].description
29// In-stock badge show: currentProduct.data[0].inventory_count > 0
30// Loading state show: currentProduct.isFetching
31// Not found show: currentProduct.isFetched && currentProduct.data.length === 0
32// Content show: currentProduct.isFetched && currentProduct.data.length > 0
33//
34// Navigate to this page from a list:
35// Workflow → Navigate → Product Detail page
36// Path parameter mapping: id → item.id

Common mistakes

Why it's a problem: Accessing currentProduct.data directly instead of currentProduct.data[0] causing 'undefined' errors

How to avoid: The collection always returns an array, even when filtering for one record. Access the first item with currentProduct.data[0]. Use a safety check in formulas: currentProduct.data[0]?.name (optional chaining) or currentProduct.data.length > 0 ? currentProduct.data[0].name : '' to prevent errors when the collection is still loading.

Why it's a problem: Forgetting to check 'Ignore if empty' on the path parameter filter, causing the collection to fetch all records

How to avoid: In the collection's Filters section, every filter bound to a path or query variable must have 'Ignore if empty' enabled. Without it, the collection fetches all records when the variable is empty (e.g., during initial page load before the parameter resolves). In Supabase collections, find the 'Apply if...' toggle on each filter.

Why it's a problem: Dynamic meta tags not appearing in social media link previews

How to avoid: Social media crawlers (Facebook, Twitter) do not execute JavaScript — they see WeWeb's empty HTML shell. Dynamic meta tags bound to collection data are invisible to these crawlers. Use Prerender.io as a prerendering proxy, or set static OG tags for the page template in Page settings → SEO & Meta Tags as a fallback.

Why it's a problem: Not handling the loading and empty states, causing blank or broken content when data is slow or missing

How to avoid: Always implement three states: (1) show a Skeleton Loader bound to collection.isFetching, (2) show a 404 message bound to isFetched && data.length === 0, and (3) show content bound to isFetched && data.length > 0. This prevents confusing blank screens and improves perceived performance.

Best practices

  • Name path parameters descriptively — use :slug for SEO-friendly URLs or :id for database ID-based routing
  • Always guard bindings with data availability checks (currentProduct.isFetched && currentProduct.data.length > 0) before rendering content
  • Use the Skeleton Loader component to give users visual feedback while the collection is fetching
  • Bind dynamic page meta tags (title, description) to collection fields in Page settings → SEO & Meta Tags so each URL has unique, relevant metadata
  • Upload a custom sitemap via App Assets to include dynamic page URLs that WeWeb's auto-generated sitemap excludes
  • Use optional chaining (currentProduct.data[0]?.field) in bindings to prevent JavaScript errors during loading states
  • For URLs that should be human-readable (blog posts, products), use a slug field in your database rather than numeric IDs

Still stuck?

Copy one of these prompts to get a personalized, step-by-step explanation.

ChatGPT Prompt

I'm building dynamic detail pages in WeWeb (a Vue.js SPA builder). My setup: Supabase database with a 'products' table, a dynamic page at /products/:id that should fetch the product matching the URL ID parameter. WeWeb auto-creates a path variable called 'id'. How do I configure the Supabase collection filter to use this path variable, and what binding formulas should I use to display product name, price, and image on the page?

WeWeb Prompt

In WeWeb, I have a dynamic page at /blog/:slug. My Supabase collection 'currentPost' is configured to filter posts where slug equals the URL path variable. The collection returns an array. Help me write the WeWeb binding formulas for: (1) showing the post title from currentPost.data[0].title, (2) showing a loading skeleton while isFetching is true, (3) showing a 404 message when no post is found, and (4) setting the page title meta tag to include the post title.

Frequently asked questions

Can I have nested dynamic routes in WeWeb, like /categories/:category/products/:id?

Yes. When creating the page, set the URL path to /categories/:category/products/:id. WeWeb creates two path variables — 'category' and 'id' — both available in the Data panel. You can configure your collection filters to use both, or use only one while the other drives conditional rendering or collection filtering on the page.

How do I make a WeWeb dynamic page work with pagination, showing 10 items per page?

Use a Query variable for the page number. Create a Query variable named 'page' with a default value of 1. In your collection, set Limit to 10 and Offset to (page - 1) * 10 using a binding formula. Add Previous/Next buttons with workflows that change the 'page' Query variable by ±1. The collection automatically re-fetches when the Query variable changes, showing the correct page of results.

Why is my dynamic page collection fetching all records instead of the filtered one?

The most common cause is a missing 'Ignore if empty' / 'Apply if' setting on the path variable filter. When the path variable is empty during initial load, the filter is ignored and all records are returned. Enable 'Ignore if empty' on the filter row in the collection configuration. The second common cause is a type mismatch — if your database ID is an integer but the URL parameter is a string, add a Number() conversion: Number(path.id) in the filter value formula.

Can I use WeWeb dynamic pages for a blog with good SEO?

WeWeb dynamic pages are not ideal for SEO-critical content like blogs because WeWeb generates SPAs without SSR. Googlebot eventually indexes JS-rendered content but with delays, and social media crawlers typically cannot. For a blog, consider: (1) using a separate SSR platform (WordPress, Webflow, or Next.js) for the public blog while using WeWeb for the authenticated app section, or (2) implementing Prerender.io as a prerendering proxy that serves cached HTML to crawlers. WeWeb has confirmed SSR is not on the 2026 roadmap.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Need help with your project?

Our experts have built 600+ apps and can accelerate your development. Book a free consultation — no strings attached.

Book a free consultation

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.