Getting started

Quick start

imgsweet is a URL-based image proxy. There is no SDK to install. You construct a URL, point your <img> tag at it, and imgsweet handles the rest.

1. Get your secret key

Sign in to app.imgsweet.com, create a key, and optionally set a domain allowlist.

2. Build a proxy URL

Take any public image URL, pass it as the url param, and add your transforms:

https://img.imgsweet.com/proxy
  ?url=https%3A%2F%2Fcdn.myapp.com%2Fphoto.jpg
  &w=800
  &q=75
  &secret=YOUR_KEY
The source URL must be percent-encoded. Use encodeURIComponent() in JS, urlencode() in PHP, or urllib.parse.quote() in Python.

3. Use it in your markup

<img
  src="https://img.imgsweet.com/proxy?url=https%3A%2F%2Fcdn.myapp.com%2Fphoto.jpg&w=800&q=75&secret=YOUR_KEY"
  alt="My photo"
/>

Authentication

Every request to /proxy must include a secret query param matching one of your API keys. Keys are managed in the dashboard.

The secret is visible in your HTML source and browser network tab. This is expected — it is not a password. Your domain allowlist is the primary abuse protection layer.

To rotate a key, go to the dashboard → Keys → Rotate. The old secret stops working immediately.

Domain allowlist

Each key has an optional list of allowed source domains. When set, the proxy rejects requests whose source URL hostname doesn't match.

Allowlist: myapp.com
cdn.myapp.com/photo.jpg — subdomain match
myapp.com/logo.png — exact match
evil.com/photo.jpg — rejected
fakemyapp.com/x.jpg — rejected

Leave the allowlist empty to allow any public domain. Recommended only during development.

Endpoint

GET https://img.imgsweet.com/proxy

Always returns image/webp with Cache-Control: public, max-age=432000 (5 days). Source images are downloaded server-side — the client never touches the origin URL.

Parameters

All parameters are passed as query string values.

Param Type Description
url string required Source image URL, percent-encoded.
secret string required Your API key secret.
w integer optional Output width in pixels (1–10000). Height auto-scales unless h is also set.
h integer optional Output height in pixels (1–10000).
fit string optional Resize strategy when both w and h are set. One of: inside (default), cover, contain, fill, outside.
q integer optional WebP quality, 1–100. Default 80.
strip boolean optional Strip EXIF metadata. Default true. Pass strip=false to preserve.
blur float optional Gaussian blur sigma (0.3–100). Useful for placeholder/preview images.
grayscale boolean optional Convert to greyscale. Pass grayscale=true.

Errors

All errors return JSON with statusCode and message.

StatusCause
401Missing or invalid secret.
403Source domain not in allowlist, or private IP blocked (SSRF guard).
402Credit balance is zero. Top up at app.imgsweet.com/billing.
429Free tier daily limit (10/day) reached.
502Source image could not be fetched (bad URL, origin down, timeout).
413Source image exceeds 25 MB.
Integration

JavaScript (browser)

A lightweight helper function — no dependency needed.

function imgsweet(url, params = {}) {
  const base = 'https://img.imgsweet.com/proxy'
  const qs = new URLSearchParams({
    url,
    secret: 'YOUR_KEY',
    ...params,
  })
  return `${base}?${qs}`
}

// Usage
img.src = imgsweet('https://cdn.myapp.com/photo.jpg', { w: 800, q: 75 })
img.src = imgsweet('https://cdn.myapp.com/avatar.jpg', { w: 64, h: 64, fit: 'cover' })

Node.js / Next.js

Keep the secret server-side in an environment variable.

// lib/imgsweet.ts
export function imgsweet(url: string, params: Record<string, string | number> = {}) {
  const qs = new URLSearchParams({
    url,
    secret: process.env.IMGSWEET_SECRET!,
    ...Object.fromEntries(
      Object.entries(params).map(([k, v]) => [k, String(v)])
    ),
  })
  return `https://img.imgsweet.com/proxy?${qs}`
}
// app/products/[id]/page.tsx (Next.js App Router)
import { imgsweet } from '@/lib/imgsweet'

export default function ProductPage({ product }) {
  return (
    <img
      src={imgsweet(product.imageUrl, { w: 800, q: 80 })}
      alt={product.name}
    />
  )
}

PHP

function imgsweet(string $url, array $params = []): string {
    $params = array_filter(array_merge([
        'url'    => $url,
        'secret' => getenv('IMGSWEET_SECRET'),
    ], $params));

    return 'https://img.imgsweet.com/proxy?' . http_build_query($params);
}

// Usage
$src = imgsweet($product->image_url, ['w' => 800, 'q' => 75]);
$avatar = imgsweet($user->avatar, ['w' => 64, 'h' => 64, 'fit' => 'cover']);

Liquid (Shopify)

Add this snippet to your theme as snippets/imgsweet.liquid:

{%- comment -%}
  Usage: {% render 'imgsweet', url: image.src, w: 800, q: 75 %}
{%- endcomment -%}

{%- assign _secret = 'YOUR_KEY' -%}
{%- capture _proxy -%}
  https://img.imgsweet.com/proxy?url={{ url | url_encode }}&secret={{ _secret }}
  {%- if w -%}&w={{ w }}{%- endif -%}
  {%- if h -%}&h={{ h }}{%- endif -%}
  {%- if fit -%}&fit={{ fit }}{%- endif -%}
  {%- if q -%}&q={{ q }}{%- endif -%}
{%- endcapture -%}
{{ _proxy | strip }}
{%- comment -%} In your template: {%- endcomment -%}
{% render 'imgsweet', url: product.featured_image.src, w: 800, q: 75 %}

Python

from urllib.parse import urlencode, quote
import os

def imgsweet(url: str, **params) -> str:
    qs = urlencode({
        "url": url,
        "secret": os.environ["IMGSWEET_SECRET"],
        **{k: v for k, v in params.items() if v is not None},
    })
    return f"https://img.imgsweet.com/proxy?{qs}"

# Usage
src = imgsweet("https://cdn.myapp.com/photo.jpg", w=800, q=75)
avatar = imgsweet("https://cdn.myapp.com/avatar.jpg", w=64, h=64, fit="cover")
Guide

Responsive images

Use srcset to serve different sizes at different breakpoints. Each unique URL combination is a separate transformation credit — but subsequent requests at the same size are free (CDN-cached).

function imgsweetSrcset(url, widths, params = {}) {
  return widths
    .map(w => `${imgsweet(url, { ...params, w })} ${w}w`)
    .join(', ')
}

// In your markup:
img.srcset = imgsweetSrcset(
  'https://cdn.myapp.com/hero.jpg',
  [400, 800, 1200, 1600],
  { q: 80 }
)
img.sizes = '(max-width: 768px) 100vw, 50vw'

CDN caching

imgsweet sets Cache-Control: public, max-age=432000 (5 days) on every response. Point any CDN at img.imgsweet.com and it will cache transformed images automatically.

Make sure your CDN uses the full URL — including query params — as the cache key. Strip only the secret param from the cache key if you want different users requesting the same image to share a cache entry.

On a cache hit, the request never reaches our origin and no credit is consumed.

Credits & billing

One credit is consumed each time a request reaches our proxy and a transformation runs. Cache hits are free.

TierCreditsPrice
Free10 / dayAlways free
Starter5,000$10 one-time
Growth15,000$25 one-time
Scale50,000$60 one-time

Credits never expire. Buy at app.imgsweet.com/billing. When your balance reaches zero, requests return 402 until you top up.

© 2026 imgsweet support@imgsweet.com