Rendex
Recipe

Cache Render Links in a Make Data Store — Render Each Item Once

Give every unique item a hosted og:image, but render it only the first time. A Make Data store remembers the URL keyed by content; a Router renders with Rendex on a cache miss and reuses the stored URL on every hit — fewer credits, instant repeats.

Last updated 2026-07-21

The Problem

When a scenario runs often over overlapping content — a webhook that fires on every page view, a re-sync that reprocesses the same records, a feed that repeats items — rendering an image every time is wasteful. You burn a credit and a few hundred milliseconds re-creating an image you already made, and if the same URL is requested a thousand times you've rendered it a thousand times. What you actually want is: render a given item once, keep the resulting URL, and hand that same URL back on every future request until the content changes.

The Solution

Make's Data store is a built-in key/value database, and it turns this into a clean cache. Key each item by something stable — a slug, an id, or a hash of the fields that go into the image. A 'Get a record' probes the store; a Router then splits into two routes with filters: the cache-hit route (a record came back) reads the stored URL and skips rendering entirely, while the cache-miss route (no record) calls Rendex's /v1/render/link for a hosted, edge-cached image URL and an 'Add a record' writes it to the store under that key. Every downstream module reads one og:image URL regardless of which route ran. New content renders once; everything else is a free store lookup — no credit, no latency.

How the Workflow Runs

Item in

A record arrives carrying a stable key — a slug, an id, or a hash of the title+subtitle.

Data store — Get

Make's Data store 'Get a record' looks the key up. It either returns a stored URL or nothing.

Router — hit / miss

A Router splits: if the record exists, take the cached URL; if not, render.

Rendex render link (miss only)

On a miss, POST /v1/render/link for a hosted, edge-cached image URL, then store it.

Reuse

Downstream reads one og:image URL either way — freshly rendered or from the store.

Input → Rendered Output

Left: a Make scenario — a webhook feeding a Data store 'Get a record', then a Router branching to two routes labelled 'cache hit → reuse URL' and 'cache miss → Rendex render link → Data store add'. Right: a data-store table with slug keys mapped to hosted og:image URLs, one row highlighted as a fresh miss.

Rendered by Rendex

What You Need

  • A Rendex API key — the free tier includes 100 renders/month with no card required.
  • A Make account with a Data store created (Data stores are on every Make plan; create one under the Data stores tab with a 'url' field).
  • A stable key per item — a slug, id, or a hash of the fields that go into the image.
  • A source that references content by that key — a CMS/Airtable record, a Sheets row, or a webhook payload.

What This Recipe Uses

Data store as a cache

Make's built-in key/value store remembers each rendered URL by content key — a persistent cache Zapier has no equivalent for, read and written inside the scenario.

Router: render only on a miss

A Router with filters splits cache-hit (reuse the stored URL, zero render) from cache-miss (render + store), so a repeated item never renders twice.

Hosted, edge-cached URL

POST /v1/render/link returns a stable hosted image URL — the right thing to persist and reuse as an og:image, not raw binary bytes.

Key by content, refresh on change

Hash the fields that determine the image so identical content hits the cache and changed content gets a fresh render automatically.

Build It

make-datastore-cache-setup.txt
# One-time: create a Data store (Data stores tab) with a text field "url".
# Then build the scenario:

1. Source          -> yields an item with a stable key ({{1.slug}})
2. Data store      (Data store > Get a record)
     Data store = your store
     Key        = {{1.slug}}          # or a hash of title+subtitle
3. Router          (Flow Control > Router)  -> two routes:

   Route A  filter: "record exists"   -> {{2.url}} IS NOT EMPTY
      3a. (nothing to render) map {{2.url}} downstream

   Route B  filter: "cache miss"      -> {{2.url}} IS EMPTY
      3b. HTTP > Make a request  -> Rendex /v1/render/link (body below)
      3c. Data store > Add/replace a record
            Key = {{1.slug}}   url = {{3b.url}}

# Downstream: read the render-link URL from whichever route ran.
body-render-link.json
// POST https://api.rendex.dev/v1/render/link  — set Parse response = YES
{
  "html": "<div style='width:1200px;height:630px;display:flex;flex-direction:column;justify-content:center;padding:72px;font-family:system-ui;color:#fff;background:linear-gradient(135deg,#0f172a,#ea580c)'><h1 style='font-size:64px;margin:0'>{{title}}</h1><p style='font-size:28px;color:#fed7aa'>{{subtitle}}</p></div>",
  "data": {
    "title": "{{1.title}}",
    "subtitle": "{{1.subtitle}}"
  },
  "format": "png",
  "width": 1200,
  "height": 630
}
// Response: { "url": "https://.../render/....png" } — an edge-cached
// hosted URL. Map {{3b.url}} into the "Add a record" step to store it.
router-filters.txt
# Route A — cache HIT (skip render):
#   Condition:  {{2.url}}   Exists / Is not empty
#
# Route B — cache MISS (render + store):
#   Condition:  {{2.url}}   Does not exist / Is empty
#
# Order matters only for fallback routes; with mutually-exclusive
# Exists/Empty filters exactly one route runs per item.
render-link.sh
# What the cache-miss route sends. The response is JSON with a hosted url.
curl -X POST https://api.rendex.dev/v1/render/link \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "html": "<div style=\"padding:72px;font-family:system-ui\"><h1>Hello</h1></div>",
    "format": "png",
    "width": 1200,
    "height": 630
  }'
# -> { "url": "https://.../render/....png" }  (store this)

100 free API calls/month — no credit card required. Get your API key and start building.

Reach for this when the same image is requested more than once and rendering every time is pure waste — high-frequency webhooks, idempotent re-syncs, feeds that revisit items. The engine is Make's Data store, which Zapier simply doesn't have: a persistent key/value table you read and write from inside the scenario. The design is a lookup, a Router, and a conditional render. 'Get a record' by your content key returns either the stored URL or nothing; the Router's two routes carry filters — one route where the record exists (reuse), one where it's empty (render + store). On the miss route, /v1/render/link is the right Rendex endpoint because it returns a hosted, edge-cached URL rather than raw bytes, which is exactly what you want to persist and reuse as an og:image. The subtle part is the key: hash the fields that actually determine the image (title, subtitle, template version) so that when content changes the key changes and you get a fresh render, but identical content always hits the cache. Set parseResponse on so {{url}} is mappable, store it with 'Add/replace a record', and after that the store answers most requests for free. It's all free-tier on the Rendex side — render/link, PNG, and data{} templating — and the Data store is Make-native flow you can grow into a full dedupe or rate-cap layer later.

Frequently Asked Questions

Related Resources