Issues Fetching Filtered CMS Items via Serverless Function Due to CORS Policy

Hello Webflow Community,

I’m working on integrating Webflow CMS with a custom events page that dynamically displays events for the next 14 days. Each day is a clickable tab, and events from the CMS should load based on the selected day. I’m using a serverless function hosted on Vercel to fetch the events to circumvent CORS policy restrictions. However, I’m encountering issues with CORS when trying to fetch data from my serverless function and properly filtering events by their start date from the Webflow CMS.

Implementation Overview:

  1. Webflow Page Script: Generates tabs for the next 14 days. Each tab click triggers a fetch request to my Vercel serverless function, passing the selected date to filter events from the Webflow CMS.
  2. Vercel Serverless Function: Interacts with the Webflow API to fetch events based on the start-date field.

Webflow Page Script:

window.addEventListener('DOMContentLoaded', () => {
  const dateContainer = document.getElementById('dateTabs');
  const today = new Date();

  // Generate date tabs
  for (let i = 0; i < 14; i++) {
    const futureDate = new Date(today);
    futureDate.setDate(futureDate.getDate() + i);
    const dateTab = document.createElement('div');
    // Setup dateTab with day letter and number, then append to dateContainer
    // On click, calls fetchEventsForDate with dateTab's dataset.date
  }

  // fetchEventsForDate makes a fetch call to the serverless function
  function fetchEventsForDate(date) {
    const url = `https://my-vercel-function.com/api/fetch-events?date=${date}`;
    fetch(url)
      .then(response => response.json())
      .then(data => updateCalendarContent(data.items))
      .catch(error => console.error('Error fetching events:', error));
  }
});

Vercel Serverless Function (api/fetch-events.js):

const fetch = require('node-fetch');

module.exports = async (req, res) => {
  const { date } = req.query;

  // Set CORS headers
  res.setHeader('Access-Control-Allow-Origin', '*');
  // Additional CORS and OPTIONS handling here

  if (!date) return res.status(400).send('Date is required');

  try {
    const collectionId = process.env.WEBFLOW_COLLECTION_ID;
    const token = process.env.WEBFLOW_API_TOKEN;
    const url = `https://api.webflow.com/collections/${collectionId}/items?filter_field=start-date&filter_value=${date}`;
    // Fetch from Webflow API and return items
  } catch (error) {
    console.error('Error fetching data:', error);
    return res.status(500).send(error.message);
  }
};

Issue:

When clicking a tab on my Webflow page, I receive a CORS policy error in the console, preventing the fetch from succeeding:

Access to fetch at 'https://my-vercel-function.com/api/fetch-events?date=2024-02-09' from origin 'https://my-webflow-site.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

Despite setting the CORS headers in my serverless function, the issue persists. Additionally, direct requests to the serverless function via the browser or tools like Postman result in a 500 Internal Server Error, indicating a potential issue with fetching data from Webflow’s API.

Questions:

  1. Has anyone experienced similar issues with CORS when using serverless functions to interact with Webflow’s API?
  2. Are there specific settings or configurations in Webflow or Vercel that I might be missing to allow for successful cross-origin requests?
  3. For filtering CMS items by date, is there a recommended approach or best practice I should follow, particularly when the start-date field is nested within fieldData?

Any insights, suggestions, or guidance would be greatly appreciated as I work to resolve these issues and implement dynamic event loading on my site.

Thank you!

I may have read too quickly, but if you’re just pulling the next 7 days of events and placing them in tab by day of the week, that’s pretty trivial. I’m not sure why you’re trying to acquire the data through a serverless function- it seems much more efficient to just use a filtered collection list or two, and then rearrange the elements into tabs.

SA5 has a new layout feature which I think does everything you need here.
If the calendar dates are also in a CMS collection then you can;

  • Dynamically create the day-of-week tabs for the next 7 days
  • Automatically retrieve the next 7 days of events, and assign them each to the correct tabs based on date

Note I haven’t had time to build out many demos, it’s a hugely powerful toolset. Hierarchical navs, CMS bound tabs, complex calendar layouts… pretty much anything that involves data-driven element arrangements.

The hint is in your console log: “No ‘Access-Control-Allow-Origin’ header is present on the requested resource.” And you’re probably looking at your serverless function, noting you are indeed setting it.

Your request is probably getting filtered out in the middleware stack. You might check your vercel.json: How can I enable CORS on Vercel?. I’m more of a AWS Lambda user when running serverless, but my experience tells me it’s middleware running before your function.

Your problem is not from the function to Webflow API since that is server-to-server.

Thanks so much for getting back, Michael.

I’m looking to generate the list of tabs and have them styled differently if:

  1. There are no dates
  2. There are some dates and the tab is inactive
  3. The tab is active.

I want to automatically generate tabs for the next 14 days whether there are dates or not in my Events collection.

Thought using server-less function would help deal with Webflow’s CORS policy and also allow me to store my Collection ID and API Key as environment variables in Vercel vs Webflow front-end.

This is the experience i’m trying to replicate: Today at Apple - Calendar - Apple

Thanks for sharing those, links. I’ll take a look and let you know if I have any questions!

Thanks for this, David.

I’ve attempted to incorporate the allowCors middleware function and restructured my function to use the allowCors pattern but am still experiencing 500 error.

The styling part isn’t difficult, I’d likely do it with pure CSS and :not(:has()).
You could also attach classes with script to give more designer-styling control.

This is an interesting scenario. The easy way is to just populate a CMS collection with the next 2 years of dates, and then you can just create a collection list filtered to the next 14 days.

SA5 Layout can databind those to tabs and then populate them with the events, I primarily use it for constructing nested arrangements.

However, the specific tab design you’re trying to recreate isn’t yet possible with SA5, it supports a text label only in v1. You have several date elements in there, so it would look a bit different.
I’ve added it to the future roadmap notes, I can see that being useful.

Another feature I’ve roadmapped is a pre-layout callback where you can execute custom code before the layout occurs. In your use case, that could be used to create 14 days of DIVs programmatically, and add the layout attributes before layout occurs - very efficient as it completely eliminates the need for the Dates collection.

Thanks for sharing your use case- even though I can’t point you to a client-side attributes-based solution that 100% covers your UX design goals, I think you should try the 100% client-side approach overall.

In addition to your current issues with CORS, I’d be concerned that if your site ever gets busy and you exceed 100 requests in a minute ( easily done with just a handful of users ), your middleware will fail. Perhaps it can cache as a contingency though.

If you are experiencing a 500 error now, but the CORS error is not being logged, then your function is running. Considering how simple your function is, it could be your env vars or you’re using a v2 API key while trying to access the v1 Legacy API (this is the one I use). If that is your issue, you just need to swap to a v1 Legacy API key from the project integrations.