Check out full review at https://internetmon.com/cocoon
This is an infrastructure review of cocoon iOS app. This post is an attempt to explain the behind the scenes of what happens when you use a app like Cocoon.
The app is used for group text, the app boasts lot of group text features including text, image/video, flight status, audio and video call. We have been trying to use Cocoon for our family chat instead of WhatsApp for quite some time now.
Download the iOS app App store here. The product website is here
Overall the app's backend is completely built on top of Google Cloud. They use Segment for logging, Sentry for crash analysis, Flightaware for pulling the flight details, google maps sdk for maps and location related features, Twilio for Video chat.
Signup Flow
Once you download the app and open the app you get to see this home screen.

As soon the app is launched you see bunch of GET requests that initialize all the libraries that are used.
Cocoon uses
Segment for logging/analytics.
Google firebase for most of the app's core functions(API's).
Google crash analytics for realtime alerting for any app crashes.
Sentry for crash analytics.
FlightAware Api for Flight searches
Twilio Video for Audio/Video calls
When the app first launched for the first time, it calls https://device-provisioning.googleapis.com/checkin and firebase logging endpoints like firebaselogging-pa.googleapis.com which actually collects detailed OS level information and sends those as POST request to these Google hostnames. This includes the phone type, i.e iPhone8, app name which is com.glasswing.cocoon, firebase sdk version information and so on.
Next call to get initialized and is the segment iOS SDK which returns all the integrations that the Cocoon app uses. Below is a copy of what the return json from segment api https://cdn-settings.segment.com/
GET response from https://cdn-settings.segment.com ( full json response in the website post)
{'integrations':
'Segment.io': {'apiKey': '<redacted>'}},
'plan': {'track': {'__default': {'enabled': True, 'integrations': {}}},
'identify': {'__default': {'enabled': True},
'anonymousId': {'enabled': True},
'authId': {'enabled': True},
'disabledStatusTypes': {'enabled': True},
'email': {'enabled': True},
'firstName': {'enabled': True},
'lastName': {'enabled': True},
'locationAltitude': {'enabled': True},
'memberId': {'enabled': True},
'name': {'enabled': True},
'networkSize': {'enabled': True},
'nickname': {'enabled': True},
'notificationPreferences': {'enabled': True},
'numberOfCocoonMembers': {'enabled': True},
'numberOfCocoons': {'enabled': True},
'permissions': {'enabled': True},
'phoneNumber': {'enabled': True},
'userId': {'enabled': True}},
'group': {'__default': {'enabled': True}}},
'edgeFunction': {}}
The use for this settings call is usually to get/set real time configurations for the app including the API Keys, various flags as you see in the response above.
There are other 3 important calls that Cocoon make are to its own backend. First one is the Cocoon app config call to this hostname firestore-dot-cocoon-beta.appspot.com/config and that gets a whole bunch of configs that are used by the cocoon app itself.
These settings have extensive sdk version that the app needs to use mainly for google firebase sdk's, there are some app level settings such as below that are returned as well. I have included a snippet from its response below.
GET response from firestore-dot-cocoon-beta.appspot.com/config
"defaultNotificationPreferences": {
"homeArrivals": false,
"posts": true,
"replies": true,
"workArrivals": false
},
"download-link": "https://itunes.apple.com/us/app/cocoon-a-space-for-family/id1439649269",
"mostInterestingMotionThreshold": 2,
"motionTracking": true,
"public-beta-link": "https://itunes.apple.com/us/app/cocoon-a-space-for-family/id1439649269",
"update-required": [
"1.0",
"1.4.0",
"1.3.5",
"1.3.4",
"1.3.3',
.......]
Next is the call to get the 'moods' which return the list of moods that Cooon offers in its in-app messaging. It uses firestore-dot-cocoon-beta.appspot.com/moods endpoint. Below is a snippet response for that API call.
GET response from firestore-dot-cocoon-beta.appspot.com/moods
{
"active": true,
"icon": "🙃",
"id": "10iBzPayIhMlQNmYnfDe",
"type": "Silly"
},
{
"active": true,
"icon": "🤓",
"id": "2QgoFLfsFZLCFy4Aepqj",
"type": "Smart"
},
{
"active": true,
"icon": "😶",
"id": "5weeGzH6B2CpJ8kj6AyJ",
"type": "Speechless"
}
Below is a screenshot of what the in-app display for these moods look like within Cocoon. Looks like these moods can be added/removed in near realtime by changing the response from the API.

Another GET call is made to firestore-dot-cocoon-beta.appspot.com/colors which returns all the color shades that are used when you create a user after you finish Signup.
GET response from firestore-dot-cocoon-beta.appspot.com/colors ( full json response in the website post)
({'name': 'red3'},
{'name': 'pink3'},
{'name': 'green1'},
{'name': 'green2'},
{'name': 'red'},
{'name': 'pink2'},
{'name': 'blue2'})
This is the screen that uses this colors API in the Cocoon app. Whatever color the backend returns is used here.

Since cocoon uses Firebase, it authenticates itself with the appid, fid..etc and the endpoint https://firebaseinstallations.googleapis.com/v1/projects/cocoon-beta/installations/ responds with session token and expirations.This is necessary for session management from firebase perspective.
Each and every user interaction, like taps, clicks, swipes..etc are all logged extensively to segment. An Example POST request snippet to the segment endpoint looks like below with all private information redacted.
POST request to https://api.segment.io/v1/batch ( full json response in the website post)
{'batch': [{'messageId': <redacted>,
'anonymousId': <redacted>,
'userId': <redacted>,
'event': 'Application Backgrounded',
'context': {'screen': {'width': 414, 'height': 896},
'device': {'manufacturer': 'Apple',
'model': 'iPhone11,8',
'id': <redacted>,
'type': 'ios',
'name': 'iPhone'},
'os': {'name': 'iOS', 'version': '13.6'},
'app': {'version': '2.0.1',
'namespace': 'com.glasswing.cocoon',
'name': 'Cocoon',
'build': '1266\\n'},
'library': {'name': 'analytics-ios', 'version': '3.9.0'},
'locale': 'en-US',
'timezone': 'America\\/Los_Angeles',
'traits': {'disabledStatusTypes': [],
'networkSize': 0,
'authId': <redacted>,
'firstName': <redacted>,
'locationAltitude': 'NOT_SPECIFIED',
'lastName': '',
'permissions': {'photos': 'authorized',
'location': 'authorizedWhenInUse',
'camera': 'notDetermined',
'bodyTemp': 'notDetermined',
'notifications': 'authorized',
'heartRate': 'notDetermined',
'workouts': 'notDetermined',
'motionActivity': 'notDetermined',
'mindfulness': 'notDetermined'},
'anonymousId': <redacted>,
'notificationPreferences': {'posts': True,
'integrations': {}},
{'messageId': <redacted>,
'anonymousId':<redacted>,
'userId': '<redacted>',
'event': 'Application Opened',
'context': {'screen': {'width': 414, 'height': 896},
'device': {'manufacturer': 'Apple',
'model': 'iPhone11,8',
'id': '<redacted>',
'type': 'ios',
'name': 'iPhone'}
'sentAt': '2020-06-29T21:19:06.908Z'}
It looks like most of the log have the same format with similar metadata, but the `event` and 'type' parameter is what has changed. When i finish the on-boarding flow, the event name was "Completed Onboarding Flow" and so on.
In addition to Cocoon sending the app events to segment, google does its own collection of data which is encrypted and heavily compressed(so, i am not able to see the actual content). Initially there is a GET request to https://app-measurement.com/sdk-exp with the app name(com.glasswing.cocoon), phone type and few other metadata. Then there is a POST call to the same hostname but different endpoint https://app-measurement.com/config with a app_instance_id which returns a bunch of config.
As you keep using the Cocoon app you see calls made to https://app-measurement.com/a endpoint with encrypted data. Google actually has list of fields that they collect, that are here. Doing a basic google search for app-measurements.com yielded these and these. It does look like google collects more information about the app usage and other metadata.
As you go through the registration process with Cocoon, they require you to verify your phone number(similar to whatsapp..etc) and also collect your email which they do not verify and stored in Mailchimp. Cocoon uses Firebase identity toolkit to send sms to the new users to verify the identity.
Once the user authentication is complete, Cocoon asks the user about allowing to sending notifications, location, health data to track steps..etc. A unique userid is created as soon as the registration is complete. The location is tracked to the exact lat, long and it looks like the google firebase sdk converts them quickly to the street address. The location context going forward is carried in all the calls between the app and the cocoon api. I am not seeing the location info sent to logs in segment.
Features
The App has bunch of features similar to what other group messaging apps have. You can
Create Groups
Send text messages
Share photo/video
Voice call and Video call
Share Location/ Checkin
Share flight status, activity information
The below sections will go through each and everyone of these features.
Create Cocoon
When you go to create a cocoon, which is a group, you click Get Started, give the Cocoon a name, then select a Nickname which is how you show up to others, then you click Create which creates the Cocoon. A POST request is made to hello-dot-cocoon-beta.appspot.com hostname with the name, nickname and color/picture payload. You can see the sample response below from the endpoint after a cocoon is created. You can see a Cocoon Id being created at this time.
POST response from hello-dot-cocoon-beta.appspot.com
{
"createdAt": 1399022832,
"createdById": "<redacted>",
"id": "<redacted>",r
"inviteCode": "YYQWRW",
"joinEnabled": true,
"membershipIds": [
"<redacted>"
],
"name": "Extended family group",
"userCount": 1,
"userIds": [
"<redacted>"
]
}
Text Messages
Each and every time a message is posted on a Cocoon by a user, a POST call is made to firestore-dot-cocoon-beta.appspot.com/bead.
You can see the actual Payload that is being sent to the above endpoint.
POST request to firestore-dot-cocoon-beta.appspot.com/bead
{
"ambient": false,
"attachments": [
{
"id": <redacted>,
"text": "Hello again",
"type": "TEXT"
}
],
"cocoonId": "<redacted>",
"createdAt": 1299026219,
"id": "<redacted>",
"membershipId": "<redacted>",
"primaryAttachmentType": "TEXT",
"reactions": [],
"replies": [],
"type": "v3",
"userId": "<redacted>"
}
For each and every text message created, a unique messageId is created. The app tells the backend to associate the messageID to a CocoonId and a userId. This helps to associate the which user sends which message.
Share Photo/Video
Cocoon like any other group messaging app allows users to share Photo/Video to the groups. It uses Google Storage to store these files. It stores a thumbnail view as well as the full image/video file that is uploaded.
This update is split into 2 calls to the Cocoon's backend. First call is a PUT request to firebasestorage.googleapis.com endpoint with a unique file name, once the file is successfully uploaded, the app does a POST to firestore-dot-cocoon-beta.appspot.com endpoint to associate the uploaded file with the user and the cocoon. Below is an example that shows the request payload that Cocoon uses to the backend.
POST request to firestore-dot-cocoon-beta.appspot.com
{
"ambient": false,
"attachments": [
{
"assets": [
{
"bucketName": "<redacted>",
"createdAt": 1399027762,
"id": "<redacted>",
"imageFilename": "<redacted>",
"mediaType": "PHOTO",
"thumbnailFilename": "<redacted>",
"videoFilename": null
}
],
"id": "<redacted>",
"type": "MEDIA",
"uploadComplete": true
}
],
"cocoonId": "<redacted>",
"createdAt": 1399027762,
"id": "<redacted>",
"membershipId": "<redacted>",
"primaryAttachmentType": "MEDIA",
"reactions": [],
"replies": [],
"type": "v3",
"userId": "<redacted>"
}
Location
Cocoon has a neat way to share Location between users within a group if you wish, this also enables check-in. If you use the checkin feature and search for Locations, Cocoon uses the google maps sdk to search and present you with relevant search results. After you select a place to check-in, a POST request is made to the firestore-dot-cocoon-beta.appspot.com/bead endpoint. Below shows a sample Request JSON being sent to the backend.
POST request to firestore-dot-cocoon-beta.appspot.com
{
"ambient": false,
"attachments": [
{
"coordinates": {
"latitude": 48.241497,
"longitude": -20.196476
},
"id": "<redacted>",
"locality": "",
"locationCategories": [
"shopping_mall",
"grocery_or_supermarket",
"restaurant",
"food",
"point_of_interest",
"store",
"establishment"
],
"pointOfInterest": "New York City Center",
"postalCode": "",
"type": "LOCATION"
}
],
"cocoonId": "<redacted>",
"createdAt": 12990239,
"id": "<redacted>",
"membershipId": "<redacted>",
"primaryAttachmentType": "LOCATION",
"reactions": [],
"replies": [],
"type": "v3",
"userId": "<redacted>"
}
Along with the checkin feature, if you click onto the other people within your Cocoon, you can see their location if they have enabled Location. This feature uses the same endpoint firestore-dot-cocoon-beta.appspot.com/location.
Below is the actual PUT request that is being sent to Cocoon's Backend.
PUT request to firestore-dot-cocoon-beta.appspot.com/location
{
"administrativeArea": "CA",
"ambientCandidate": true,
"country": "United States",
"countryCode": "US",
"createdAt": 1299929434,
"id": "<redacted>",
"isStationary": false,
"lastSeenAt": 1299929434,
"latitude": 37.8199286,
"locality": "San Francisco",
"longitude": -122.4804438,
"postalCode": "94016",
"streetAddress": "Golden Gate Bridge",
"userId": "<redacted>"
}
Flight Status
Cocoon has this neat feature that we personally use all the time when our family is travelling. A user would be able to add a flight information to the group and the flight updates are sent to the group. Cocoon uses FlightAware api to pull flight information and display in the app. Cocoon uses flights-dot-cocoon-beta.appspot.com/flight endpoint to post the flight information once the user selects a flight.
POST request to flights-dot-cocoon-beta.appspot.com/flight
{
"cocoonId": "<redacted>",
"destination": "LAX",
"flightIdentifier": "AAL75-1398449229-airline-0021",
"origin": "MIA",
"userId": "<redacted>"
}
Audio/Video rooms
Nowadays almost all the group chat apps should have audio and video capabilities. Its usually harder to implement these natively because of the complexity involved. With Cocoon having these capabilities, i was intrigued to dig in more to see how their implementation looks like.
Cocoon doesn't have a native implementation of video feature. They use twilio Video API in their implementation.
Twilio has concept called rooms that can be controlled in the backend. You have the ability to create rooms on the fly from the backend, in this case if a group wants to meet, Cocoon backend will create a room for that group and when the user clicks join will send the access token to the client. The client uses that access token and using the twilio sdk will join the room hence making this work. These calls are made via UDP with WebRTC protocol.
As soon as you click `invite to talk` in your Cocoon, the app calls https://gather-dot-cocoon-beta.appspot.com/accessToken with the cocoonId, userId and so on. The backend responds with access token token, roomId and the user ID. Below is a sample response from the Cocoon Backend.
GET response from gather-dot-cocoon-beta.appspot.com/accessToken
{
"accessToken": "<redacted>",
"clientId": "<redacted>",
"roomId": "<redacted>"
}
The Twilio SDK uses these accessToken and the roomId to connect the user the group and the call starts. roomId is uniqiue as cocoonId here. When a second user wants to connect to the same call, they get a new unique accessToken with the same roomId. Twilio is hosted on AWS, so when you use the video calls feature you are actually connecting to AWS.
Doing a packet capture shows DNS resolution for global.vss.twilio.com
endpoint when the app tries to establish the video room. More information on the twilio Video IP Ranges here

Packet Capture
You can see the UDP connection to 44.234.69.104 which is a connection to Twilio App in US West Coast (Oregon) AWS region.
Overall Impression
The iOS App's user experience overall is refreshing. I wish we have apps like these that are successful.
Data collected is mostly consistent with what you would expect from other apps, maybe turn off Google's data collection if its unnecessary
There is no end to end encryption which is a big red flag for any messaging app
Except the flight status feature, there is no other killer feature that makes the app standout other than the design and user experience.
https://cocoon.com/ website that explains the product should be much better, the website is all black and white and seems fishy, while the app experience is much much better.