Creating API wrappers with Webflow Cloud

A primer on using Webflow Cloud to create an API wrapper, or proxy, to an external API.

Creating API wrappers with Webflow Cloud

Raymond Camden
Senior Developer Evangelist
View author profile
Raymond Camden
Senior Developer Evangelist
View author profile
Table of contents

Webflow Cloud is a powerful tool to add nearly any kind of functionality imaginable to your Webflow site.

Developers can host and bind a Next.js or Astro app to their Webflow site, with the ability to pull Webflow design systems into their apps (thanks to the power of DevLink). They can also harness additional features from Webflow Cloud’s Cloudflare integration, including multiple options for data storage. In general, most people may consider using Webflow Cloud to build visual apps for their site visitors, but it can be used for purely “data centric” applications, as well. Today, I'm going to demonstrate one powerful example of this: creating an API wrapper.

When using remote APIs in client-side JavaScript code, you have to be careful to not expose API keys that can be stolen and used elsewhere. Creating a lightweight, server-side proxy makes this easier to prevent because the front-end code never contains the key. Even better, creating this proxy allows for:

  • Data shaping: An API may return a lot of information you simply don't need. It may also return information in a way that's not helpful to the front-end code. Your server-side proxy can remove, add, and modify the result of the remote API. Additionally, you can shape both the output and the input.  
    • A remote API might support two arguments, but your proxy can hard-code one of them, permanently fixing its value. This gives you full control over not only how the remote API is called, but what it's allowed to return.
  • Caching: By implementing a lightweight cache you can store and reuse the results of the API without having to hit the external resource. This can also reduce costs since many APIs will charge per request.
  • Flexibility: In the most extreme case, you may need to completely switch to a new API provider. Since your front-end code is calling your Webflow Cloud app proxy, you can swap in the new provider, shape the response to match the previous one, and you’re done. You could even build a proxy that uses two or more API providers, switching between them as needed.

In this post, I'll demonstrate this in action, iterating over a few versions to show how an initial implementation can be improved. 

Getting the weather: Pirate style

One of my favorite APIs is Pirate Weather, a replacement for the discontinued Dark Sky API. It provides really detailed weather information for a great price: free (there are limits and you can, and should, consider donating if you make use of the API). Using the API requires getting a key, and then perusing the docs. The simplest call looks like this:

https://api.pirateweather.net/forecast/YOUR_KEY/YOUR_LATITUDE,YOUR_LONGITUDE

This will return a huge amount of data for a specific location, including the general forecast, a daily forecast, an hourly forecast, and even weather alerts.

For our Webflow site, we want to make use of this API but have it proxied to an Astro Webflow Cloud app. Our proxy will also hard-code a location for Lafayette, Louisiana, which has this latitude and longitude: 30.471165, -91.147385.

I started off following our guide on initializing a Webflow Cloud site and selected Astro as my framework. I took the default page, index.astro, and renamed it to index.js to create a server endpoint. And with that, I got to hacking.

Version one: A new hope for APIs

The initial version was simply a wrapper and nothing more. It specifies a location and uses the exclude feature of the Pirate Weather API to help reduce the size of what's returned:

export const config = {
    runtime: "edge",
};

async function getForecast(lat, lon, key) {
    let req = await fetch(`https://api.pirateweather.net/forecast/${key}/${lat},${lon}?exclude=minutely,hourly,flags`);
    let result = await req.json();
    return result;
}

export async function GET({ request, locals }) {

    const PIRATE_API_KEY = locals.runtime.env.PIRATE_API_KEY || process.env.PIRATE_API_KEY;
    
    if(!PIRATE_API_KEY) {
        throw('Missing env key');
    }

    let result = await getForecast(30.471165, -91.147385, PIRATE_API_KEY);

    return new Response(
        JSON.stringify(result),
        { headers: { 'Content-Type': 'application/json' } }
    );
}

As you can see, no input arguments are checked, this API route will just call the external remote API and return the data as is. This is the simplest and most direct way to accomplish what we need — adding a weather report (for one location, at least) to our Webflow site. You can run this yourself here.

Ok, that's good, but can we make it better?

Version two: The API strikes back

If you tried the URL above and saw the results, you could see it was quite intensive. Lots and lots of data. That's a great selling point for the Pirate Weather API (especially since it's free), but it includes way more data than we need. Let's address this by shaping the data. I added a new function, shapeData, to my code just for that purpose:

function shapeData(data) {

    // We already know the location
    delete data.latitude; 
    delete data.longitude;
    // First, reduce daily forecast to 3 days
    data.daily.data = data.daily.data.slice(0, 3);

    // This is a list of keys we can remove from currently/daily data
    const keysToRemove = ['time', 'apparentTemperatureMax', 'apparentTemperatureMaxTime', 'apparentTemperatureMin', 'apparentTemperatureMinTime','apparentTemperatureHigh', 'apparentTemperatureHighTime', 'apparentTemperatureLow', 'apparentTemperatureLowTime', 'cloudCover', 'icon', 'nearestStormBearing', 'apparentTemperature', 'dewPoint', 'pressure', 'uvIndex', 'ozone', 'visibility'];

    for(let key of keysToRemove) {
        delete data.currently[key];
        for(let day of data.daily.data) {
            delete day[key];
        }
    }

    return data;
}

The shapeData function does a few things. First, it removes a couple of top level items we don't need, like the location, which we literally had hard coded in the request. Next, it slims down the daily forecast to just three days. Finally, it removes a lot of data we don't need on our site. If you're curious about what they are (and the rest of the values we left alone), you can check out the response docs for details. But for now, I’ve removed the ones I didn't think were terribly important.

The last change is to simply call it:

let result = shapeData(await getForecast(30.471165, -91.147385, PIRATE_API_KEY));

The net result is a lot less data that would have been wasted on our site anyway. You can hit this version here.

If you're curious about the savings: my devtools reported the first version at 3KB and this version at 1.8KB — a reduction of over a third in response payload size. The initial version is still really small, but you can imagine how this kind of trimming adds up with a larger or more complex API.

Version three: Return of the cache

For the third and final version, I made the ultimate upgrade: server-side caching. For this, I used the key value store feature of Webflow Cloud. After following the set up guide, my code had access to Cloudflare's KV system, which is super useful for caching.

Adding caching to the code involved two steps:

  • Is the value in the cache? Return it!
  • If it isn't, do the normal remote API call and cache it.

Here's the entirety of the change:

let result = await kv.get('forecast');
if(!result) {
    console.log('forcast not in cache');
    result = shapeData(await getForecast(30.471165, -91.147385, PIRATE_API_KEY));
    // cache for ten minutes
    await kv.put('forecast', JSON.stringify(result), { expirationTtl: 600 });
} else {
    console.log('forecast from cache');
    result = JSON.parse(result);
}

As you can see, the code attempts to fetch the forecast from cache first. Cached items can expire, and the system handles that by itself  — it just won't exist if it's expired. If the cache result isn't there, the code calls the API as usual and then stores the value in the cache for ten minutes. Note that I stringify the result first, and in the conditional block where the cache did exist, I parse the JSON string (the final result is stringified anyway, but this keeps it simpler).

Now if you hit the endpoint, you'll either get a cached or non-cached version depending on site traffic. In my quick test, I saw the response come in about half the time, but those savings will depend on the speed of the remote API, size of the data, and so forth.

If you want to see this for yourself, you can check out the repo here. The code for API wrappers are in the src/pages directory.

Next steps

Creating API proxies is not a new idea, but being able to use Webflow Cloud to host these proxies along with your site brings an additional level of cohesion and flexibility to what you can build on the Webflow platform. Give this a shot and let us know what you've built!

Alex Halliday
CEO
AirOps
Learn more
Aleyda Solis
International SEO Consultant and Founder
Orainti
Learn more
Barry Schwartz
President and Owner
RustyBrick, Inc
Learn more
Chris Andrew
CEO and Cofounder
Scrunch
Learn more
Connor Gillivan
CEO and Founder
TrioSEO
Learn more
Eli Schwartz
Author
Product-led SEO
Learn more
Ethan Smith
CEO
Graphite
Learn more
Evan Bailyn
CEO
First Page Sage
Learn more
Gaetano Nino DiNardi
Growth Advisor
Learn more
Jason Barnard
CEO and Founder
Kalicube
Learn more
Kevin Indig
Growth Advisor
Learn more
Lily Ray
VP SEO Strategy & Research
Amsive
Learn more
Marcel Santilli
CEO and Founder
GrowthX
Learn more
Michael King
CEO and Founder
iPullRank
Learn more
Rand Fishkin
CEO and Cofounder
SparkToro, Alertmouse, & Snackbar Studio
Learn more
Stefan Katanic
CEO
Veza Digital
Learn more
Steve Toth
CEO
Notebook Agency
Learn more
Sydney Sloan
CMO
G2
Learn more

Full-stack web apps hosted on Webflow

Extend the power of Webflow's platform by deploying full-stack web apps and dynamic, on-brand web experiences alongside your Webflow site.

Read now

Last Updated
February 18, 2026
Category

Related articles

Webflow meets Claude: Design, structure, and manage sites right from Claude
Webflow meets Claude: Design, structure, and manage sites right from Claude

Webflow meets Claude: Design, structure, and manage sites right from Claude

Webflow meets Claude: Design, structure, and manage sites right from Claude

Development
By
Vic Plummer
,
,
Read article
Expose your Webflow CMS with a simple API
Expose your Webflow CMS with a simple API

Expose your Webflow CMS with a simple API

Expose your Webflow CMS with a simple API

Development
By
Raymond Camden
,
,
Read article
Writing effective prompts for the Webflow MCP
Writing effective prompts for the Webflow MCP

Writing effective prompts for the Webflow MCP

Writing effective prompts for the Webflow MCP

Development
By
Vic Plummer
,
,
Read article
API development: The complete guide to development best practices
API development: The complete guide to development best practices

API development: The complete guide to development best practices

API development: The complete guide to development best practices

Development
By
Webflow Team
,
,
Read article

Get started for free

Try Webflow for as long as you like with our free Starter plan. Purchase a paid Site plan to publish, host, and unlock additional features.

Get started — it’s free
Watch demo

Try Webflow for as long as you like with our free Starter plan. Purchase a paid Site plan to publish, host, and unlock additional features.