How to use Unsplash imagery and photography in a Webflow store

Learn how to add Unsplash photography to a Webflow store without breaking the license.

How to use Unsplash imagery and photography in a Webflow store

Ismail Ajagbe
Technical Author
View author profile
Ismail Ajagbe
Technical Author
View author profile
Table of contents

Unsplash photography can dress a store. It cannot be the product, and the API asks for things the license does not.

Most new stores hit the same wall on day one. The products exist, and the layout works. But the whole thing still looks unfinished because it lacks photography: no lifestyle shot behind the hero, or nothing on the category cards. Sometimes, the About page has no texture.

Unsplash is the usual answer, and for a Webflow store it is a good one. What trips people up is that the license and the API are two different sets of rules, and the API asks for things the license does not.

This guide covers what you can do with Unsplash photography in a commercial store, then builds the integration in a way that keeps you within both sets of terms.

What do you need to use Unsplash images in a Webflow store?

You need an Unsplash developer account and a server-side place to store the access key. The key cannot live in a client component, because anything in the browser bundle is public the moment your site is.

To start, confirm that you get these in place first:

  • An Unsplash account registered for the API, with an application created
  • Your access key, which the API expects as a Client-ID authorization header
  • A Webflow site with the collection or pages the imagery will decorate
  • A Webflow Cloud project running a Next.js app, plus Node.js 22.13.0 or higher locally, the floor set by Webflow CLI 2.x

A new application starts in demo mode, which matters more than it sounds and is covered in step one. Before any of that, though, a licensing question determines whether this integration fits your store.

What the Unsplash license lets a store do

Unsplash photography can decorate a store. It cannot be the product. That distinction separates a compliant integration from a legal problem, and the license states it plainly rather than burying it in terms.

The Unsplash License permits commercial use with no permission needed. It lists two things that are not permitted: compiling images to replicate a similar or competing service, and selling images "without significant modification". A store that sells prints, wallpapers or downloadable packs of Unsplash photos is doing the second thing.

Pulling images through the API adds obligations on top of the license, which is where most integrations drift out of compliance without noticing:

What you want to do Under the plain Unsplash License When you pull images through the API
Use a photo as lifestyle or background imagery on a product page Allowed, commercially, with no permission needed Allowed, but the CDN URL returned by the API must be the one you embed
Sell the photo itself as a print, wallpaper or download Not permitted. The license says images cannot be sold without significant modification Stricter. The guidelines bar using the API to sell unaltered photos, directly or indirectly
Credit the photographer and Unsplash Appreciated, not required Required. Every application must provide attribution under the API Guidelines
Copy the file and serve it from your own CDN or Webflow assets Permitted by the license itself Not permitted. The guidelines require hotlinking the URLs the API returns
What you want to do → Under the plain Unsplash License → When you pull images through the API
Use a photo as lifestyle or background imagery on a product page
Allowed, commercially, with no permission needed
Allowed, but the CDN URL returned by the API must be the one you embed
Sell the photo itself as a print, wallpaper or download
Not permitted. The license says images cannot be sold without significant modification
Stricter. The guidelines bar using the API to sell unaltered photos, directly or indirectly
Credit the photographer and Unsplash
Appreciated, not required
Required. Every application must provide attribution under the API Guidelines
Copy the file and serve it from your own CDN or Webflow assets
Permitted by the license itself
Not permitted. The guidelines require hotlinking the URLs the API returns

The bottom row catches Webflow builds specifically. The instinct is to fetch a photo, upload it into Webflow assets, and reference it like any other image, which is exactly what the guidelines ask you not to do.

5 steps to add Unsplash imagery to a Webflow store

The build uses a Route Handler that queries Unsplash, a CMS field that holds a URL rather than a file, and an attribution block on the front end. Nothing here downloads a photo.

Each step assumes the one before it, so work through them in order.

1. Register the application and understand demo mode

Create an application in your Unsplash developer account and copy the access key. What matters more than the key is the mode: a new application starts in demo, and Unsplash rate-limits demo applications to 50 requests per hour.

Fifty an hour is workable for building and useless for a live store, because a single page that fetches on render can burn through it during your own testing. Production mode raises it to 1,000 requests an hour, but it requires an application and approval, and approval depends on following the API Guidelines rather than being automatic.

Plan for that gap. Build against demo, cache aggressively, and apply for production before you launch, not after traffic arrives.

End this step with an access key and a clear note on which mode you are in, because the failure it causes later looks nothing like a rate limit.

2. Put the access key behind a Route Handler

The Unsplash API expects the key in an Authorization: Client-ID header, which means the request has to be made somewhere the key isn't visible. A client component won't work, because everything it imports ships to the browser.

The handler below searches Unsplash and returns only what the front end needs: a hotlinkable URL, the alt text, the credit, and the download location for later. It deliberately does not return the file.

Create it at app/api/imagery/route.ts:

// app/api/imagery/route.ts
import { NextRequest, NextResponse } from 'next/server'

type UnsplashPhoto = {
  id: string
  urls: { regular: string; small: string }
  alt_description: string | null
  links: { download_location: string }
  user: { name: string; username: string }
}

export async function GET(request: NextRequest) {
  const query = request.nextUrl.searchParams.get('q')
  const key = process.env.UNSPLASH_ACCESS_KEY

  if (!key || !query) {
    return NextResponse.json({ error: 'Missing key or query' }, { status: 400 })
  }

  const res = await fetch(
    `https://api.unsplash.com/search/photos?query=${encodeURIComponent(query)}&per_page=12`,
    { headers: { Authorization: `Client-ID ${key}` } }
  )

  // Quota is reported in headers on every response, not by a status code.
  if (res.headers.get('X-Ratelimit-Remaining') === '0') {
    return NextResponse.json({ error: 'Rate limited' }, { status: 429 })
  }

  if (!res.ok) {
    return NextResponse.json({ error: 'Unsplash request failed' }, { status: 502 })
  }

  const data = (await res.json()) as { results: UnsplashPhoto[] }

  // Keep the CDN URL, never a copy of the file.
  return NextResponse.json({
    photos: data.results.map((p) => ({
      id: p.id,
      url: p.urls.regular,
      alt: p.alt_description ?? '',
      downloadLocation: p.links.download_location,
      credit: { name: p.user.name, username: p.user.username },
    })),
  })
}

Note how the quota is read. Unsplash returns your rate limit status in X-Ratelimit-Limit and X-Ratelimit-Remaining headers on every response rather than committing to a status code, and a 403 from Unsplash means missing permissions rather than throttling.

Deploy this, and a search request should return a list of URLs on the images.unsplash.com domain.

3. Store the URL, never the file

This step keeps the integration compliant. Add a plain text field to your CMS collection for the image URL, and a second for the credit, rather than an image field holding an uploaded asset.

The API documentation is explicit that the URLs it returns must be the ones you embed, a practice it calls hotlinking, so that photo views can be counted and passed back to the photographer. Copying the file into Webflow assets breaks that chain even though the license alone would allow it.

Write the record with the create item endpoint, remembering that fieldData keys are field slugs, not Designer labels. A correct item holds a URL you can paste into a browser, and no uploaded asset.

4. Render the image with its attribution

Bind the stored URL directly to the image element's source. Because the file lives on the Unsplash CDN, you get their delivery and resizing parameters for free, and you can request a narrower version by storing urls.raw alongside it and appending parameters such as &w=750&dpr=2, which is the sizing method the documentation specifies.

Attribution is not optional here. The license describes credit as appreciated, but the API Guidelines require every application to attribute the photographer and Unsplash, and attribution is one of the guidelines an application is measured against when it applies for production access.

Put the credit near the image rather than in a footer nobody reads, linking the photographer's profile and Unsplash, with ?utm_source=your_app_name&utm_medium=referral appended to both links as the guidelines require. When this step is done, every photo on the page carries a visible line naming who took it.

5. Trigger the download event when a photo is chosen

The guidelines ask for one more call with no visible effect that is easy to skip. When your application downloads a photo, trigger a GET request to the photo's download_location endpoint.

It is a counter, not a fetch. The docs are clear that it is for tracking only and shouldn't be used to embed the photo, so keep serving the URL you already stored.

Add the call where a person actually commits to a photo, such as an editor picking one for a product:

// Call this when a person actually chooses a photo, not on every render.
export async function trackSelection(downloadLocation: string) {
  await fetch(downloadLocation, {
    headers: {
      Authorization: `Client-ID ${process.env.UNSPLASH_ACCESS_KEY}`,
    },
  })
  // The response carries a url field, but it is not what you embed.
  // Keep using the urls.* value you already stored.
}

Firing it on every page render would inflate the photographer's stats and burn your rate limit. With this in place, the integration satisfies the three API obligations that shape the build: hotlinking, attribution, and download tracking. Read the full guidelines before applying for production, since they also cover key confidentiality and resale.

What causes Unsplash images to fail on a Webflow site?

Four failures account for most of it: a silent rate limit, a broken hotlink, missing attribution at approval and imagery used in a way the license doesn't cover.

The first two look like bugs, and the last two look like nothing until someone else raises them:

Images stop loading after a burst of testing

Cause: The demo mode ceiling of 50 requests per hour, reached faster than expected because a component fetched on every render rather than caching. Only API calls count toward it, since image file requests to the CDN do not, so what actually stops is the search returning URLs rather than the photos themselves loading.

Fix: Cache results and store the chosen URL in the CMS so the page renders without calling Unsplash. Hit the API when an editor picks an image, not when a visitor loads a page. If you are genuinely at production scale, apply for production access, but treat the fetch-per-render pattern as the real bug, since production limits are a ceiling rather than a license to poll.

Images render locally and break on the live site

Cause: The image was downloaded during development and referenced from a local path or a temporary asset, so nothing resolves once the app is deployed. It is the same mistake as re-hosting, just less deliberate.

Fix: Reference the urls.regular value from the API response and store that string. A quick check: open the CMS record and paste the field value into a browser. If it doesn't load a photo on the Unsplash CDN, the record has the wrong value, and the page will break as soon as it leaves your machine.

Check this across every record, not just the one that broke, because a build that downloaded one image usually downloaded all of them, and the rest will fail as soon as anyone visits those pages.

Production access is refused

Cause: Missing or incomplete attribution. Approval depends on following the API Guidelines, and attribution is easy to skip because the license makes credit optional.

Fix: Credit the photographer and Unsplash visibly wherever a photo appears, with links back to both, before you apply rather than after being refused. Check the download trigger at the same time, since it is the other guideline that is invisible when missing and is easy to leave out of a build that otherwise works.

Reviewers look at the running application, not your intentions, so put the credit somewhere someone can see it in a screenshot, and keep it on every surface that shows a photo rather than only the page you expect to be checked.

The store sells something built from the photos

Cause: The license permits commercial use but not resale. Selling a photo as a print, a wallpaper pack, or a downloadable asset means selling the image itself, which the license doesn't permit without significant modification.

Fix: Treat Unsplash photography as the packaging rather than the product. Use it for backgrounds, category tiles and editorial imagery around what you sell. If a photograph needs to be the thing in the cart, license it from a stock provider whose terms cover resale, because no amount of API compliance changes what the license permits.

This is the one failure in this list with consequences outside your own logs, so it is worth settling before the store launches rather than after a photographer notices their work on sale.

What you can build next with Unsplash and Webflow

Once imagery arrives as data rather than as uploads, the store gets easier to run: an editor picks a photo from a search inside your own admin page, the CMS holds the URL, and the design team never touches an asset panel.

The same handler can front any media provider you pay for later, which matters if the catalog outgrows free photography. If your store also sells across regions, our global e-commerce guide covers the translation layer that sits alongside it.

For design-time placement rather than an API integration, see the Webflow and Unsplash integration, which is a separate route with its own terms rather than an exception to the guidelines above.

For deeper customization beyond what that route handles, Webflow's developer docs cover Route Handlers, the CMS API and the rest of the Webflow Cloud runtime.

Frequently asked questions

Can I sell products that use Unsplash photos?

You can sell products you photographed or designed that happen to sit on an Unsplash background. You cannot sell the photograph itself. The license says you can't sell images without significant modification, so prints and wallpaper packs are out.

Is attribution actually required?

It depends on how you got the image. The license calls credit appreciated rather than required. The API Guidelines require every application to attribute the photographer and Unsplash, so pulling images through the API makes attribution mandatory.

Why can't I upload the images to Webflow?

The API requires hotlinking the URLs it returns so photo views reach the photographer. Copying files to your own assets breaks that. Store the URL in a text field instead of uploading the file.

What is the download endpoint for?

Tracking only. You trigger it when your application performs a download so the photographer's counter increments. It is not the URL you embed, and firing it on every page view inflates stats and wastes your rate limit.

How many requests do I get?

A new application sits in demo mode at 50 requests per hour, which is enough to build against but not to serve traffic. Production mode raises it to 1,000 requests per hour, but requires an application and approval to comply with the guidelines.


Last Updated
September 4, 2026
Category

Related articles


verifone logomonday.com logospotify logoted logogreenhouse logoclear logocheckout.com logosoundcloud logoreddit logothe new york times logoideo logoupwork logodiscord logo
verifone logomonday.com logospotify logoted logogreenhouse logoclear logocheckout.com logosoundcloud logoreddit logothe new york times logoideo logoupwork logodiscord logo

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.