Create an iOS Scriptable widget to show backyard bird visitors

Guides

Author

Jeff Mann

Date Published

In this tutorial, I will explain how to create an iOS Scriptable widget that displays the bird visitors in your backyard. By combining data from a BirdNET-Pi station and BirdWeather.com, we can develop a fun widget that showcases the diversity of feathered friends that visit our gardens.

You can change the code to modify colors and titles to your liking.
Click to enlarge

You can change the code to modify colors and titles to your liking.

Data sources

BirdNET-Pi and BirdWeather.com The foundation of our iOS Scriptable widget relies on two crucial data sources: your BirdNET-Pi station and BirdWeather.com.

BirdNET-Pi

BirdNET-Pi is an open-source project that utilizes a Raspberry Pi and a microphone to record bird songs and identify the species using machine learning. By integrating BirdNET-Pi with your backyard, you can collect valuable data on bird visitors throughout the day.

BirdWeather

To get the data we need for the widget, we will utilize the BirdWeather.com API. BirdWeather is a website that provides BirdNET-Pi detections from across the world. By combining the bird identification data from your specific BirdNET-Pi station on BirdWeather we can create a dynamic and informative widget that shows the number of daily detections, top visitor species, and latest species.


Creating the iOS Scriptable widget

Assuming we have the above data sources, let's dive into the code required to build our iOS Scriptable widget.

Start by installing the Scriptable app from the App Store. Open the app and create a new script by tapping the "+" icon.

Simply paste the code below into your newly-created widget. You'll replace [STATION_TOKEN] with the token you received by emailing tim@birdweather.com.

The script code

1const url = 'https://app.birdweather.com/api/v1/stations/[STATION_TOKEN]/species/?limit=5'
2const url2 = 'https://app.birdweather.com/api/v1/stations/[STATION_TOKEN]/stats'
3const url3 = 'https://app.birdweather.com/api/v1/stations/[STATION_TOKEN]/stats/?period=all'
4const url4 = 'https://app.birdweather.com/api/v1/stations/[STATION_TOKEN]/detections/?limit=1'
5
6let req = await new Request(url)
7let req2 = await new Request(url2)
8let req3 = await new Request(url3)
9let req4 = await new Request(url4)
10
11var result = await req.loadJSON()
12var dailyresult = await req2.loadJSON()
13var lifetimeresult = await req3.loadJSON()
14var latestspecies = await req4.loadJSON()
15
16// Create widget
17let w = new ListWidget()
18w.backgroundColor = new Color("#60a97c");
19
20// #Title
21
22t1 = w.addText("🦉 BirdNet-Pi Station stats");
23t1a = w.addText("Species acoustically detected in the past 24 hours");
24t1.font = Font.boldSystemFont(24);
25t1.textColor = Color.yellow();
26t1a.font = Font.boldSystemFont(12);
27t1a.textColor = Color.white();
28
29
30w.addSpacer()
31
32t0 = w.addText(dailyresult.detections + " ");
33t0a = w.addText("total detections");
34t0.font = Font.boldSystemFont(48);
35t0.textColor = Color.yellow();
36t0a.font = Font.boldSystemFont(18);
37t0a.textColor = Color.white();
38t0b = w.addText(lifetimeresult.detections + " total lifetime detections");
39t0b.font = Font.regularSystemFont(14);
40t0b.textColor = Color.white();
41t0c = w.addText("Latest visitor: " + latestspecies.detections[0].species.commonName);
42t0c.font = Font.regularSystemFont(14);
43t0c.textColor = Color.white();
44
45w.addSpacer()
46t2ai = w.addText("Top birds");
47t2ai.font = Font.boldSystemFont(18);
48t2ai.textColor = Color.white();
49// #1
50
51const bird1 = (result.species[0].commonName);
52const detections1 = (result.species[0].detections.total);
53
54 t2 = w.addText("1. " + bird1 + " - " + detections1 + " times");
55
56t2.textColor = Color.white();
57t2.font = Font.regularSystemFont(14);
58
59// #2
60
61const bird2 = (result.species[1].commonName);
62const detections2 = (result.species[1].detections.total);
63
64t3 = w.addText("2. " + bird2 + " - " + detections2 + " times");
65
66t3.textColor = Color.white();
67t3.font = Font.regularSystemFont(14);
68
69//3
70
71const bird3 = (result.species[2].commonName);
72const detections3 = (result.species[2].detections.total);
73
74t4 = w.addText("3. " + bird3 + " - " + detections3 + " times");
75
76t4.textColor = Color.white();
77t4.font = Font.regularSystemFont(14);
78
79//4
80
81const bird4 = (result.species[3].commonName);
82const detections4 = (result.species[3].detections.total);
83
84t4 = w.addText("4. " + bird4 + " - " + detections4 + " times");
85
86t4.textColor = Color.white();
87t4.font = Font.regularSystemFont(14);
88//5
89
90const bird5 = (result.species[4].commonName);
91const detections5 = (result.species[4].detections.total);
92
93t4 = w.addText("5. " + bird5 + " - " + detections5 + " times");
94
95t4.textColor = Color.white();
96t4.font = Font.regularSystemFont(14);
97// wrap up
98
99if (config.runsInWidget) {
100 Script.setWidget(w)
101} else {
102 w.presentLarge()
103}
104Script.complete()

Adding it to your home screen

Once the widget is created, you can run and preview it by pressing the ▶️ button.

Add a widget to your home screen, choose to add a Scriptable widget, and select the large size.

Long press on your home screen and click on the new widget, and select the script you created. Once saved, your widget should display your BirdWeather data.

The BirdWeather widget on my home screen
Click to enlarge

The BirdWeather widget on my home screen

Enjoy!

Related Posts

Plausible Analytics iOS widget for top pages using Scriptable

Use this code and the Scriptable app to make an iOS widget for Plausible Analytics stats.

Comments from the community

Leave a comment

P

Pete Johnson

Mar 3, 2026

I made a small change to display the species count alongside total detections. I changed t0 = w.addText(dailyresult.detections); to t0 = w.addText(dailyresult.detections + " | " + dailyresult.species); Works great.

P

Pete Johnson

Mar 3, 2026

Thanks for posting this and providing instructions. Great work!