Skip to content

feat: add native Daily.co video calls for Cal Video deep links#66

Draft
PeerRich wants to merge 3 commits intomainfrom
devin/1774878566-daily-video-deeplink
Draft

feat: add native Daily.co video calls for Cal Video deep links#66
PeerRich wants to merge 3 commits intomainfrom
devin/1774878566-daily-video-deeplink

Conversation

@PeerRich
Copy link
Copy Markdown
Member

@PeerRich PeerRich commented Mar 30, 2026

Summary

When a booking's meeting URL is a Cal Video link, the app now opens a native video call screen powered by Daily.co's React Native SDK instead of opening the browser. The app also registers as a handler for app.cal.com/video/* URLs via iOS Universal Links and Android App Links, so tapping these URLs outside the app (e.g. in Safari, Chrome, email) can open the native video call directly.

Two URL resolution paths:

  • In-app (booking detail screens): The Cal.com API already returns the direct Daily.co room URL (meetco.daily.co/<room-name>) in the booking's meetingUrl field. When tapping "Join", we detect this with isDailyRoomUrl() and pass it straight to the video-call screen.
  • Deep links (app.cal.com/video/<booking-uid>): The URL path contains a booking UID, not a Daily room name. The deep link handler extracts the UID and passes it as a bookingUid param. The video-call screen then fetches the booking via getBookingByUid() and resolves the actual Daily.co room URL from the response.

Changes:

  • Added @daily-co/react-native-daily-js and peer dependencies (@daily-co/react-native-webrtc, react-native-background-timer, react-native-get-random-values)
  • Created video-call.tsx screen with Daily.co CallObject API (join, leave, mic/camera toggle, camera flip, participant video rendering). Accepts either a direct url param or a bookingUid param with async resolution.
  • Created utils/cal-video.ts with URL detection and resolution utilities:
    • isDailyRoomUrl() — detects direct meetco.daily.co URLs (from API)
    • isCalVideoWebUrl() / getBookingUidFromCalVideoUrl() — detects and parses app.cal.com/video/<uid> URLs (from deep links)
    • resolveDailyRoomUrl() — async function that resolves either URL type to a joinable Daily.co room URL, fetching the booking via API when needed
  • Updated handleJoinMeeting in all three booking detail screens to route Daily.co URLs to the native screen, falling back to browser for other URLs (Zoom, Google Meet, etc.)
  • Registered the video-call route as a fullScreenModal in _layout.tsx
  • Added @daily-co/config-plugin-rn-daily-js Expo plugin and iOS camera/microphone permission descriptions
  • Added iOS Universal Links (applinks:app.cal.com in associated domains entitlement)
  • Added Android App Links (intentFilters for https://app.cal.com/video/*)
  • Added deep link URL listener in root layout handling both cold start (getInitialURL) and warm start (addEventListener("url"))

Review & Testing Checklist for Human

  • Verify deep link → API resolution works end-to-end: Deep links pass a bookingUid to the video-call screen, which calls getBookingByUid() to resolve the Daily.co room URL. Confirm the API returns meetingUrl with a meetco.daily.co URL for Cal Video bookings. If the field name or shape differs, the resolution will silently fail and show "No meeting URL provided".
  • Review deep link + auth interaction: The URL listener fires inside RootLayoutContent which gates on isAuthenticated. If a deep link arrives when the user is logged out, verify behavior is acceptable (currently it would try to push /video-call but the user would see the login screen, and the API call to resolve the booking UID would likely fail).
  • Test on a real device/simulator: This integrates native WebRTC modules — lint/typecheck passing does not guarantee runtime correctness. Test joining an actual Cal Video call, verify camera/mic work, and test the leave flow.
  • Server-side AASA & assetlinks setup required: iOS Universal Links need https://app.cal.com/.well-known/apple-app-site-association (bundle ID com.cal.companion, team ID ADWKXDJV75). Android App Links need https://app.cal.com/.well-known/assetlinks.json. Without these, OS-level deep linking will not activate.
  • Verify @daily-co/react-native-webrtc@124.0.6-daily.1 compatibility with Expo SDK 55 / React Native 0.83.1.

Recommended test plan:

  1. Build the app with bun run mobile:ios or bun run mobile:android
  2. Open a booking that has a Cal Video meeting URL → should open native video call screen
  3. Verify camera preview, mic toggle, camera flip, and leave button all work
  4. Open a booking with a Zoom/Google Meet URL → should still open in browser
  5. Test error state (e.g., invalid room URL) → should show error with "Go Back" button
  6. Test deep link from Safari: tap https://app.cal.com/video/<booking-uid> → should resolve the booking and join the call natively (requires server-side AASA/assetlinks)

Notes

  • No runtime testing was performed — only lint and typecheck verification.
  • The server-side apple-app-site-association and assetlinks.json files must be deployed to app.cal.com for OS-level deep linking to activate. The client-side configuration is complete in this PR.
  • resolveDailyRoomUrl() in cal-video.ts imports getBookingByUid from the services layer, making this utility file capable of async API calls. This is a deliberate design choice to keep the resolution logic centralized.

Link to Devin session: https://app.devin.ai/sessions/780a107626be4877919ffc13b29b1ead
Requested by: @PeerRich

- Install @daily-co/react-native-daily-js and peer dependencies
- Add @daily-co/config-plugin-rn-daily-js Expo plugin
- Create video-call screen with Daily.co CallObject API
- Route Cal Video URLs (app.cal.com/video/*) to native video call
- Add camera/microphone permission descriptions for iOS
- Fall back to browser for non-Cal Video meeting URLs

Co-Authored-By: peer@cal.com <peer@cal.com>
@devin-ai-integration
Copy link
Copy Markdown
Contributor

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR that start with 'DevinAI' or '@devin'.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

- Add iOS universal links (associatedDomains: applinks:app.cal.com)
- Add Android intent filters for https://app.cal.com/video/*
- Handle incoming deep links in root layout (cold + warm start)
- Fix Daily.co subdomain to meetco.daily.co

Co-Authored-By: peer@cal.com <peer@cal.com>
@vercel
Copy link
Copy Markdown

vercel bot commented Mar 30, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
cal-companion-chat Ignored Ignored Mar 30, 2026 2:10pm

Request Review

…mapping

The Cal Video URL path (app.cal.com/video/<id>) contains a booking UID,
not a Daily room name. Updated the flow:

- In-app: meetingUrl from API is already a meetco.daily.co URL, pass directly
- Deep links: extract booking UID, pass to video-call screen which fetches
  the booking via API and resolves the actual Daily.co room URL
- Added resolveDailyRoomUrl() async function for booking UID resolution
- Removed incorrect getDailyRoomUrl() that mapped UID directly to Daily URL

Co-Authored-By: peer@cal.com <peer@cal.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant