
When building Slipi, I wanted both the iOS app and its widget to display the same sleep data — in real time. But I quickly learned that normal UserDefaults doesn’t automatically share data between the app and its widget.
That’s when I discovered App Groups — Apple’s way of allowing different parts of the same app (like the main app and extensions) to share information securely. It was my first time setting it up, and here’s what I learned from the process.
⚙️ Setting Up App Groups

To make shared data possible, I had to configure App Groups correctly in the Apple Developer portal and Xcode.
Here are the steps I followed:
-
Create App ID for the Containing App
This represents the main iOS app (e.g., Slipi). -
Create App ID for the Extension (Widget)
This represents the widget extension that displays sleep info. -
Create an App Group
In the Developer portal, I created a new App Group with an identifier likegroup.com.example.slipi. -
Assign the App Group to the Containing App’s App ID
This allows the main app to read and write data to the shared group container. -
Assign the App Group to the Extension’s App ID
This connects the widget to the same container, enabling both sides to access shared data.
📚 Reference: Today Widget by @pgpt10 on GitHub
💻 Using Shared UserDefaults
After setting up App Groups, I needed to update my code to use a shared data container instead of the default one.
Previously, I used:
let defaults = UserDefaults.standardBut now, I had to reference the shared App Group:
let defaults = UserDefaults(suiteName: "group.com.example.slipi")This new suiteName connects both the app and the widget to the same UserDefaults container, so any change in one will be reflected in the other.
💡 Tip: Make sure the group identifier matches exactly with the one registered in the Apple Developer portal — a typo here can break data sharing completely.
🧠 What I Learned
- Normal UserDefaults doesn’t sync between apps and extensions — App Groups are required.
- You must create and assign the App Group to both the main app and the widget’s App IDs.
- Always use the exact group identifier when initializing UserDefaults(suiteName:).
- Shared UserDefaults makes it easy to sync lightweight data like settings, scores, or small state info between app components.
After I got this working, seeing the sleep data instantly appear in the widget felt super satisfying — a small detail that made the overall experience more seamless.
✨ Closing Thoughts
This was a simple yet valuable lesson in app architecture and data sharing. Even though it’s just a few extra setup steps, understanding App Groups taught me how iOS apps handle isolation and communication securely.
It’s small discoveries like this that make iOS development exciting — every technical limitation opens a door to learning something new