{
  "slug": "cache-weather-api-wix-velo",
  "title": "Cache a Weather API for a Wix Velo Site",
  "metaDescription": "Cache OpenWeather responses for Wix Velo sites at the edge. RealComposer hides the appid key and serves shared results in under 10ms to every visitor.",
  "headline": "Live weather widgets on Wix without per-visitor API calls",
  "category": "caching",
  "categoryLabel": "Edge Caching & Rate Limits",
  "urgency": 8,
  "clientPlatform": "Wix Velo",
  "upstreamServices": [
    "OpenWeather"
  ],
  "searchIntentQuery": "cache weather api for wix velo site",
  "directAnswerSummary": "Calling OpenWeather from Wix page code exposes the appid key and spends one call per visitor. A RealComposer pipeline keeps the key in the vault, caches results by location for ten minutes, and returns only temperature, condition, and icon for your Wix weather widget.",
  "problem": {
    "title": "Why weather widgets burn OpenWeather quota on Wix",
    "explanation": "Travel and venue sites on Wix often show current weather on every page view. Without a shared cache, popular pages make thousands of identical upstream calls, and the appid key placed in page code can be copied by anyone.",
    "risks": [
      "OpenWeather appid exposed in Wix page code",
      "Free and paid call limits reached during traffic spikes",
      "Full forecast payloads sent for a three-field widget"
    ]
  },
  "solutionSteps": [
    {
      "stepNumber": 1,
      "title": "Store credentials in Secret Vault",
      "description": "Save OPENWEATHER_KEY in RealComposer so the value never enters the Wix Velo project."
    },
    {
      "stepNumber": 2,
      "title": "Configure the edge pipeline",
      "description": "Add the upstream steps with vault header injection, set allowed origins, and map only the fields the screen binds."
    },
    {
      "stepNumber": 3,
      "title": "Render the weather widget in Velo",
      "description": "Call your workspace edge URL with a restricted rc_live_ client token.",
      "codeSnippet": "import { fetch } from 'wix-fetch';\n\n$w.onReady(async () => {\n  const res = await fetch('https://realcomposer.com/v1/workspace/cache-weather-api-wix-velo?lat=44.98&lon=-93.27', {\n    headers: { Authorization: 'Bearer rc_live_client_token' },\n  });\n  const w = await res.json();\n  $w('#tempText').text = `${Math.round(w.temp)}°`;\n});"
    }
  ],
  "pipelineConfig": {
    "name": "Cache a Weather API for a Wix Velo Site",
    "method": "GET",
    "cacheTtlSeconds": 600,
    "authMode": "client_token",
    "steps": [
      {
        "stepKey": "weather",
        "upstreamUrlTemplate": "https://api.openweathermap.org/data/2.5/weather?lat={{query.lat}}&lon={{query.lon}}&units=imperial&appid={{secrets.OPENWEATHER_KEY}}",
        "httpMethod": "GET",
        "headersTemplate": {},
        "timeoutMs": 3000
      }
    ],
    "outputMapping": {
      "version": 1,
      "fields": [
        {
          "targetPath": "temp",
          "sourceStep": "weather",
          "sourcePath": "main.temp",
          "type": "number"
        },
        {
          "targetPath": "condition",
          "sourceStep": "weather",
          "sourcePath": "weather.0.main"
        },
        {
          "targetPath": "icon",
          "sourceStep": "weather",
          "sourcePath": "weather.0.icon"
        }
      ]
    }
  },
  "sampleBloatedInput": {
    "coord": {
      "lon": -93.27,
      "lat": 44.98
    },
    "weather": [
      {
        "id": 800,
        "main": "Clear",
        "description": "clear sky",
        "icon": "01d"
      }
    ],
    "base": "stations",
    "main": {
      "temp": 41.2,
      "feels_like": 36.1,
      "pressure": 1021,
      "humidity": 58
    },
    "visibility": 10000,
    "wind": {
      "speed": 8.1,
      "deg": 300
    },
    "sys": {
      "country": "US",
      "sunrise": 1762952400,
      "sunset": 1762987200
    }
  },
  "sampleSlimmedOutput": {
    "temp": 41.2,
    "condition": "Clear",
    "icon": "01d"
  },
  "curlSnippet": "curl -X GET \"https://realcomposer.com/v1/workspace/cache-weather-api-wix-velo\" \\\n  -H \"Authorization: Bearer rc_live_client_token\"",
  "faqs": [
    {
      "question": "How do I share cache entries across nearby visitors?",
      "answer": "Round latitude and longitude to two decimals in page code before calling the pipeline, so visitors in the same area hit the same cache key."
    },
    {
      "question": "Can Wix backend code call the pipeline instead?",
      "answer": "Yes. Calling from a backend web module also works and keeps the client token off the page, at the cost of an extra hop through Wix servers."
    }
  ],
  "relatedRecipeSlugs": [
    "cache-weather-api-edge",
    "call-airtable-from-wix-velo-securely",
    "cache-third-party-api-at-edge"
  ],
  "links": {
    "page": "https://realcomposer.com/recipes/cache-weather-api-wix-velo",
    "markdown": "https://realcomposer.com/recipes/cache-weather-api-wix-velo.md",
    "json": "https://realcomposer.com/recipes/cache-weather-api-wix-velo.json",
    "install": "https://realcomposer.com/dashboard/pipelines/new?recipe=cache-weather-api-wix-velo&via=agent"
  }
}