# Recipe: Lightning Forecast

import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from "zudoku/ui/Accordion";

export const StepHeader = ({ n, children }) => (
  <span style={{ display: "inline-flex", alignItems: "center", gap: "0.75rem" }}>
    <span style={{
      display: "inline-flex",
      alignItems: "center",
      justifyContent: "center",
      width: "1.75rem",
      height: "1.75rem",
      minWidth: "1.75rem",
      borderRadius: "9999px",
      backgroundColor: "#F05514",
      color: "#FFFFFF",
      fontSize: "0.875rem",
      fontWeight: 600,
      flexShrink: 0,
      lineHeight: 1,
    }}>
      {n}
    </span>
    <span>{children}</span>
  </span>
);

This recipe shows how to fetch lightning probability forecasts for a given location.

:::note
**These recipes are teaching examples — not production code.**

- **Host:** examples use the development host **apidev.accuweather.com**. Switch to **api.accuweather.com** for production.
- **Production hardening:** GZIP compression, caching, retries with exponential backoff, and error handling are not included. See the [Best Practices](/developers/best-practices) guide.
:::

## Scenario

> "I want to show users whether lightning is likely near their location in the next 2 hours."

---

<Accordion type="multiple" defaultValue={["step-1"]} className="my-6">

<AccordionItem value="step-1">
  <AccordionTrigger><StepHeader n={1}>Make the request</StepHeader></AccordionTrigger>
  <AccordionContent>

Call the Lightning forecasts endpoint with a latitude and longitude.

**Endpoint:**
```
GET https://apidev.accuweather.com/lightning/v1/forecasts/geoposition?apikey={YOUR_API_KEY}&q={latitude},{longitude}
```

<CodeTabs syncKey="language">

```ts title="TypeScript"
const apiKey = "{YOUR_API_KEY}";
const lat = 38.63;
const lon = -90.2;

const res = await fetch(
  `https://apidev.accuweather.com/lightning/v1/forecasts/geoposition?apikey=${apiKey}&q=${lat},${lon}`
);
const data: Record<string, any> = await res.json();
console.log(`Forecast initialized at: ${data.initDateTime}`);
```

```python title="Python"
import requests

API_KEY = "{YOUR_API_KEY}"
lat, lon = 38.63, -90.2

resp = requests.get(
    "https://apidev.accuweather.com/lightning/v1/forecasts/geoposition",
    params={"apikey": API_KEY, "q": f"{lat},{lon}"},
)
data = resp.json()
print(f"Forecast initialized at: {data['initDateTime']}")
```

```csharp title="C#"
using var client = new HttpClient();

var apiKey = "{YOUR_API_KEY}";
var lat = 38.63;
var lon = -90.2;

var response = await client.GetAsync(
    $"https://apidev.accuweather.com/lightning/v1/forecasts/geoposition?apikey={apiKey}&q={lat},{lon}");
var data = await response.Content.ReadAsStringAsync();
```

```java title="Java"
HttpClient client = HttpClient.newHttpClient();
String apiKey = "{YOUR_API_KEY}";
double lat = 38.63, lon = -90.2;

HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create(
        "https://apidev.accuweather.com/lightning/v1/forecasts/geoposition?apikey="
        + apiKey + "&q=" + lat + "," + lon))
    .build();

HttpResponse<String> response =
    client.send(request, HttpResponse.BodyHandlers.ofString());
```

```bash title="bash"
curl "https://apidev.accuweather.com/lightning/v1/forecasts/geoposition?apikey={YOUR_API_KEY}&q=38.63,-90.2"
```

</CodeTabs>

  </AccordionContent>
</AccordionItem>

<AccordionItem value="step-2">
  <AccordionTrigger><StepHeader n={2}>Inspect the response</StepHeader></AccordionTrigger>
  <AccordionContent>

The response contains a `forecasts` array with probability values at 10-minute intervals for the next 2 hours.

```json
{
  "latitude": 38.63,
  "longitude": -90.2,
  "initDateTime": "2026-03-30T20:10:00Z",
  "forecasts": [
    {
      "startDateTime": "2026-03-30T20:10:00Z",
      "startEpochTime": 1774901400,
      "probability": 0.0
    },
    {
      "startDateTime": "2026-03-30T20:20:00Z",
      "startEpochTime": 1774902000,
      "probability": 0.0
    },
    {
      "startDateTime": "2026-03-30T20:30:00Z",
      "startEpochTime": 1774902600,
      "probability": 15.0
    },
    {
      "startDateTime": "2026-03-30T20:40:00Z",
      "startEpochTime": 1774903200,
      "probability": 45.0
    },
    {
      "startDateTime": "2026-03-30T20:50:00Z",
      "startEpochTime": 1774903800,
      "probability": 62.0
    }
  ]
}
```

:::tip
The `probability` value ranges from `0.0` (no lightning expected) to `100.0` (lightning very likely). Each interval covers 10 minutes.
:::

  </AccordionContent>
</AccordionItem>

<AccordionItem value="step-3">
  <AccordionTrigger><StepHeader n={3}>Check for lightning risk</StepHeader></AccordionTrigger>
  <AccordionContent>

Scan the forecast intervals and flag any with elevated probability:

<CodeTabs syncKey="language">

```ts title="TypeScript"
const maxProb = Math.max(...data.forecasts.map((f: any) => f.probability));
const riskyIntervals = data.forecasts.filter((f: any) => f.probability >= 30);

if (maxProb >= 50) {
  console.log("High lightning risk — stay indoors.");
} else if (maxProb >= 30) {
  console.log("Moderate lightning risk — monitor conditions.");
} else {
  console.log("Low lightning risk for the next 2 hours.");
}

for (const f of riskyIntervals) {
  const time = new Date(f.startDateTime).toLocaleTimeString();
  console.log(`  ${time}: ${f.probability.toFixed(0)}% probability`);
}
```

```python title="Python"
from datetime import datetime

max_prob = max(f["probability"] for f in data["forecasts"])
risky = [f for f in data["forecasts"] if f["probability"] >= 30]

if max_prob >= 50:
    print("High lightning risk — stay indoors.")
elif max_prob >= 30:
    print("Moderate lightning risk — monitor conditions.")
else:
    print("Low lightning risk for the next 2 hours.")

for f in risky:
    time = datetime.fromisoformat(f["startDateTime"]).strftime("%H:%M")
    print(f"  {time}: {f['probability']:.0f}% probability")
```

```csharp title="C#"
using System.Text.Json;

var doc = JsonDocument.Parse(data);
var forecasts = doc.RootElement.GetProperty("forecasts");

double maxProb = 0;
foreach (var f in forecasts.EnumerateArray())
{
    var prob = f.GetProperty("probability").GetDouble();
    if (prob > maxProb) maxProb = prob;
}

Console.WriteLine(maxProb >= 50
    ? "High lightning risk — stay indoors."
    : maxProb >= 30
        ? "Moderate lightning risk — monitor conditions."
        : "Low lightning risk for the next 2 hours.");

foreach (var f in forecasts.EnumerateArray())
{
    var prob = f.GetProperty("probability").GetDouble();
    if (prob >= 30)
    {
        var time = DateTime.Parse(f.GetProperty("startDateTime").GetString()!).ToString("HH:mm");
        Console.WriteLine($"  {time}: {prob:F0}% probability");
    }
}
```

```java title="Java"
import org.json.JSONObject;
import org.json.JSONArray;
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;

var doc = new JSONObject(data);
var forecasts = doc.getJSONArray("forecasts");
var fmt = DateTimeFormatter.ofPattern("HH:mm");

double maxProb = 0;
for (int i = 0; i < forecasts.length(); i++) {
    double prob = forecasts.getJSONObject(i).getDouble("probability");
    if (prob > maxProb) maxProb = prob;
}

System.out.println(maxProb >= 50
    ? "High lightning risk — stay indoors."
    : maxProb >= 30
        ? "Moderate lightning risk — monitor conditions."
        : "Low lightning risk for the next 2 hours.");

for (int i = 0; i < forecasts.length(); i++) {
    var obj = forecasts.getJSONObject(i);
    double prob = obj.getDouble("probability");
    if (prob >= 30) {
        var time = OffsetDateTime.parse(obj.getString("startDateTime")).format(fmt);
        System.out.println("  " + time + ": " + String.format("%.0f", prob) + "% probability");
    }
}
```

```bash title="bash"
# Parse with jq — find intervals above 30%
curl -s "https://apidev.accuweather.com/lightning/v1/forecasts/geoposition?apikey={YOUR_API_KEY}&q=38.63,-90.2" \
  | jq '.forecasts[] | select(.probability >= 30) | {time: .startDateTime, probability}'
```

</CodeTabs>

  </AccordionContent>
</AccordionItem>

</Accordion>

---

## Key response fields

| Field | Type | Description |
|-------|------|-------------|
| `latitude` | Number | Latitude of the requested point |
| `longitude` | Number | Longitude of the requested point |
| `initDateTime` | String | Forecast initialization time in ISO 8601 format |
| `forecasts[].startDateTime` | String | Start of the 10-minute interval in ISO 8601 format |
| `forecasts[].startEpochTime` | Integer | Start of the interval as epoch seconds |
| `forecasts[].probability` | Number | Percentage likelihood of at least one lightning strike during the interval |

---

## Complete code sample

Copy a full, runnable example that fetches the lightning forecast, assesses risk, and flags high-risk intervals.

<CodeTabs syncKey="language">

```ts title="TypeScript"
const API_KEY = "{YOUR_API_KEY}";
const lat = 38.63;
const lon = -90.2;

// Step 1: Fetch the forecast
const res = await fetch(
  `https://apidev.accuweather.com/lightning/v1/forecasts/geoposition?apikey=${API_KEY}&q=${lat},${lon}`
);
const data: Record<string, any> = await res.json();

console.log("\n⚡ Lightning Forecast — Next 2 Hours");
console.log("━".repeat(42) + "\n");

// Step 2: Overall risk assessment
const maxProb = Math.max(...data.forecasts.map((f: any) => f.probability));

if (maxProb >= 50) console.log("🔴 High lightning risk — stay indoors.\n");
else if (maxProb >= 30) console.log("🟡 Moderate lightning risk — monitor conditions.\n");
else console.log("🟢 Low lightning risk for the next 2 hours.\n");

// Step 3: Flag risky intervals
const riskyIntervals = data.forecasts.filter((f: any) => f.probability >= 30);
if (riskyIntervals.length > 0) {
  console.log("Intervals above 30%:");
  for (const f of riskyIntervals) {
    const time = f.startDateTime.slice(11, 16);
    console.log(`  ${time}  ${f.probability.toFixed(0)}%`);
  }
  console.log("");
}
```

```python title="Python"
from datetime import datetime
import requests

API_KEY = "{YOUR_API_KEY}"
lat, lon = 38.63, -90.2

# Step 1: Fetch the forecast
resp = requests.get(
    "https://apidev.accuweather.com/lightning/v1/forecasts/geoposition",
    params={"apikey": API_KEY, "q": f"{lat},{lon}"},
)
data = resp.json()

print("\n⚡ Lightning Forecast — Next 2 Hours")
print("━" * 42 + "\n")

# Step 2: Overall risk assessment
max_prob = max(f["probability"] for f in data["forecasts"])

if max_prob >= 50:
    print("🔴 High lightning risk — stay indoors.\n")
elif max_prob >= 30:
    print("🟡 Moderate lightning risk — monitor conditions.\n")
else:
    print("🟢 Low lightning risk for the next 2 hours.\n")

# Step 3: Flag risky intervals
risky = [f for f in data["forecasts"] if f["probability"] >= 30]
if risky:
    print("Intervals above 30%:")
    for f in risky:
        time = datetime.fromisoformat(f["startDateTime"]).strftime("%H:%M")
        print(f"  {time}  {f['probability']:.0f}%")
    print()
```

```csharp title="C#"
using System.Text.Json;

var apiKey = "{YOUR_API_KEY}";
var lat = 38.63;
var lon = -90.2;

// Step 1: Fetch the forecast
using var client = new HttpClient();
var response = await client.GetStringAsync(
    $"https://apidev.accuweather.com/lightning/v1/forecasts/geoposition?apikey={apiKey}&q={lat},{lon}");

using var doc = JsonDocument.Parse(response);

// Parse forecasts into a list so we only enumerate once
var forecasts = doc.RootElement.GetProperty("forecasts")
    .EnumerateArray()
    .Select(f => new {
        Time = DateTime.Parse(f.GetProperty("startDateTime").GetString()!).ToString("HH:mm"),
        Probability = f.GetProperty("probability").GetDouble()
    })
    .ToList();

Console.WriteLine("\n⚡ Lightning Forecast — Next 2 Hours");
Console.WriteLine(new string('━', 42) + "\n");

// Step 2: Overall risk assessment
var maxProb = forecasts.Max(f => f.Probability);

Console.WriteLine(maxProb >= 50
    ? "🔴 High lightning risk — stay indoors.\n"
    : maxProb >= 30
        ? "🟡 Moderate lightning risk — monitor conditions.\n"
        : "🟢 Low lightning risk for the next 2 hours.\n");

// Step 3: Flag risky intervals
var risky = forecasts.Where(f => f.Probability >= 30).ToList();
if (risky.Count > 0)
{
    Console.WriteLine("Intervals above 30%:");
    foreach (var f in risky)
        Console.WriteLine($"  {f.Time}  {f.Probability:F0}%");
    Console.WriteLine();
}
```

```java title="Java"
import org.json.JSONObject;
import org.json.JSONArray;
import java.net.URI;
import java.net.http.*;
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;

public class LightningForecast {
    public static void main(String[] args) throws Exception {
        String apiKey = "{YOUR_API_KEY}";
        double lat = 38.63, lon = -90.2;

        // Step 1: Fetch the forecast
        HttpClient client = HttpClient.newHttpClient();
        HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create(
                "https://apidev.accuweather.com/lightning/v1/forecasts/geoposition?apikey="
                + apiKey + "&q=" + lat + "," + lon))
            .build();

        HttpResponse<String> response =
            client.send(request, HttpResponse.BodyHandlers.ofString());

        var doc = new JSONObject(response.body());
        var forecasts = doc.getJSONArray("forecasts");
        var fmt = DateTimeFormatter.ofPattern("HH:mm");

        System.out.println("\n⚡ Lightning Forecast — Next 2 Hours");
        System.out.println("━".repeat(42) + "\n");

        // Step 2: Overall risk assessment
        double maxProb = 0;
        for (int i = 0; i < forecasts.length(); i++) {
            double p = forecasts.getJSONObject(i).getDouble("probability");
            if (p > maxProb) maxProb = p;
        }

        System.out.println(maxProb >= 50
            ? "🔴 High lightning risk — stay indoors.\n"
            : maxProb >= 30
                ? "🟡 Moderate lightning risk — monitor conditions.\n"
                : "🟢 Low lightning risk for the next 2 hours.\n");

        // Step 3: Flag risky intervals
        var risky = new ArrayList<JSONObject>();
        for (int i = 0; i < forecasts.length(); i++) {
            var obj = forecasts.getJSONObject(i);
            if (obj.getDouble("probability") >= 30) risky.add(obj);
        }
        if (!risky.isEmpty()) {
            System.out.println("Intervals above 30%:");
            for (var obj : risky) {
                var time = OffsetDateTime.parse(obj.getString("startDateTime")).format(fmt);
                System.out.printf("  %s  %.0f%%%n", time, obj.getDouble("probability"));
            }
            System.out.println();
        }
    }
}
```

```bash title="bash"
#!/bin/bash
API_KEY="{YOUR_API_KEY}"
LAT=38.63
LON=-90.2

# Step 1: Fetch the forecast
DATA=$(curl -s "https://apidev.accuweather.com/lightning/v1/forecasts/geoposition?apikey=${API_KEY}&q=${LAT},${LON}")

# Step 2: Overall risk assessment
MAX=$(echo "$DATA" | jq '[.forecasts[].probability] | max')

echo ""
echo "⚡ Lightning Forecast — Next 2 Hours"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""

if (( $(echo "$MAX >= 50" | bc -l) )); then
  echo "🔴 High lightning risk — stay indoors."
elif (( $(echo "$MAX >= 30" | bc -l) )); then
  echo "🟡 Moderate lightning risk — monitor conditions."
else
  echo "🟢 Low lightning risk for the next 2 hours."
fi

# Step 3: Flag risky intervals
echo ""
echo "Intervals above 30%:"
echo "$DATA" | jq -r '.forecasts[] | select(.probability >= 30) | "  \(.startDateTime[11:16])  \(.probability)%"'
```

</CodeTabs>

---

## Next steps

- [Real-Time Lightning](/recipes/lightning-realtime) — see current strikes near a location
- [Historical Lightning](/recipes/lightning-historical) — analyze past lightning activity
- [Lightning Parameters](/developers/lightning/parameters) — full API reference
