Social images
Daily dashboard previews, browser rendering, storage, and traffic limits.
Dashboard pages advertise a 1200 × 630 image through Open Graph and Twitter large-image metadata. Public projects include their name, section, and uploaded logo. Public accounts receive a section-specific preview. Private accounts and personal settings use generic Glossia branding.
Image identity and lifetime
The image digest includes the displayed content, project logo revision, template, styles, fonts, brand asset, dependency lockfile, and current day in Coordinated Universal Time. Changing any of these creates a new address. Sorting the attributes and signing at midnight keeps the complete address stable throughout the day.
The signed payload cannot be changed by a visitor. It is valid for two days, but only the current day's payload may generate a missing image. Yesterday's stored images remain readable. Query parameters never become object-store keys.
Successful images are persisted under og/images/<digest>.jpg in the configured
Amazon Simple Storage Service-compatible bucket.
Only an explicit missing-object response starts generation. Storage failures
return an uncacheable temporary failure, without starting Chrome. An upload must
succeed before a newly rendered image is served.
Rendering and limits
Rendering uses Carta with BrowseChrome, the same stack as Tuist's image renderer. The supervised pool contains two browsers. Each render has a 15-second deadline; each application instance permits at most twelve new renders per minute. Stored-image requests do not consume that allowance.
Cachex combines concurrent requests for the same image and retains up to 100 images for five minutes. A nonblocking PostgreSQL advisory lock prevents different application replicas from rendering the same image simultaneously. Other replicas receive a temporary failure and can retry once the object exists.
The template pairs a Noora section badge with Glossia's warm background, serif heading, gradient accent, and understated footer. Source Serif 4 and Inter are bundled locally so previews do not depend on a font service. Fonts and raster logos are embedded. The document's content security policy blocks scripts and external resources. Logos are loaded only from the application's avatar storage prefix and are limited to five million bytes, matching project uploads.
Response behavior
| Result | Status | Cache behavior |
|---|---|---|
| Stored or newly persisted image | 200 | Public, one day, immutable |
| Invalid, expired, or altered signature | 404 | No storage |
| Yesterday's image missing from storage | 404 | No storage |
| Browser busy, render failure, or storage unavailable | 503 | No storage; retry after 60 seconds |
| Origin request allowance exceeded | 429 | No storage; retry interval in response |
The origin permits thirty requests per minute per client address, including invalid requests.
Cloudflare
The social-images-rate-limit.yaml resource in the infrastructure repository
matches GET and HEAD requests under /og/, including verified crawlers. It
permits twenty requests per ten seconds per client address and Cloudflare
location. Exceeding the limit blocks requests for ten seconds. The general
public-page challenge rules exclude this path so image crawlers never need to
solve a browser challenge.
Cloudflare's default cache behavior
caches .jpg responses and honors origin cache headers. Keep the signed query
string in the default cache key. Do not apply an overriding cache duration that
caches error responses or ignores no-store. The deterministic signature avoids
one cache entry per page request.
Deploy the infrastructure resource alongside the application. Ensure the origin is reachable only through the trusted ingress, since forwarded client addresses are trusted by the existing request limiter. The browser pool and render budget also bound distributed misses and direct-origin requests.
Local configuration
Set GLOSSIA_OG_IMAGES=true to enable the browser pool in development. Install
Google Chrome or Chromium, build assets with mix assets.build, and configure
the existing object-storage environment variables:
GLOSSIA_S3_ACCESS_KEY_IDGLOSSIA_S3_SECRET_ACCESS_KEYGLOSSIA_S3_ENDPOINTGLOSSIA_S3_REGIONGLOSSIA_S3_BUCKET
Run mix ecto.setup and mix phx.server. With storage configured, seeds give
the public dev/glossia project a logo. Inspect the og:image metadata on a
dashboard page to get its signed image address.