Note
Update: Push notifications are finally implemented! π₯³ Get notified instantly when someone reaches out through your website.
A simple real-time messaging app built with Flutter, Firebase (Auth, Cloud Firestore) and Supabase (Edge Functions, Database) - designed for a single purpose: let people reach you directly from your personal website.
No need to share social media links. No need for third-party contact forms.
Just embed Talkest on your website, and anyone with a Google account can start a conversation with you instantly.
Why does this exist?
I built Talkest because I wanted a simple "get in touch" solution for my portfolio website. Instead of redirecting visitors to social media, they can just chat with me right there, powered by a Flutter Web widget embedded directly into the page.
- Real-time messaging β Powered by Cloud Firestore with live message streaming
- Google Sign-In β One-tap authentication, no extra account needed
- Light & Dark theme β With system theme detection and manual toggle
- QR Code profile β Each user gets a personal QR code for quick contact sharing
- QR Scanner β Scan someone's QR code to start a chat instantly
- Start chat by email β Find and message any registered user by their email address
- Editable display name β Customize how your name appears to others
- Embeddable chat widget β Deploy the Flutter Web build and embed it on any website via iframe
- Native mobile app β Install the Android app to monitor and reply to incoming messages on the go
- Push Notifications β High-priority alerts with heads-up display, custom sounds, and auto-dismissal when chat is read.
- Deep Linking β Clicking a notification takes you directly to the relevant chat room.
| Platform | Status | Link |
|---|---|---|
| Android | β Available | Github release |
| Web | β Available | khip01.github.io/talkest |
| Embedded mode | β Available | Used on my portfolio |
| iOS | β Not yet | No Mac device available for development |
| Login | Chat List | Messaging |
![]() |
![]() |
![]() |
| Embed mode β Landing page on portfolio website |
|---|
![]() |
| Embed mode β Chat view on portfolio website |
|---|
![]() |
| Category | Technology |
|---|---|
| Framework | Flutter (Dart) |
| Backend (Primary) | Firebase (Auth, Cloud Firestore) |
| Backend (Functions) | Supabase (Edge Functions, Database) |
| Push Notifications | Firebase Cloud Messaging (FCM v1) |
| Authentication | Google Sign-In |
| State Management | BLoC + Provider |
| Routing | GoRouter |
| Deployment | GitHub Pages (Web), APK (Android) |
- Flutter SDK
- Firebase project with Authentication and Cloud Firestore enabled
- Google OAuth 2.0 Client ID (for Flutter Web only)
Collections and documents are created automatically when the app runs for the first time β no manual setup needed. Below is the database structure for reference:
βββ app_users (collection)
β βββ {uid} (document)
β βββ name: string
β βββ displayName: string
β βββ email: string
β βββ photoUrl: string
β βββ provider: string
β βββ createdAt: timestamp
β βββ updatedAt: timestamp
β βββ lastLoginAt: timestamp
β
βββ chats (collection)
βββ {chatId} (document)
βββ type: string ("direct")
βββ participants: array [uid1, uid2]
βββ createdAt: timestamp
βββ updatedAt: timestamp
βββ unreadCount: map { uid1: number, uid2: number }
βββ lastMessage: map
β βββ id: string
β βββ senderId: string
β βββ text: string
β βββ type: string
β βββ createdAt: timestamp
β βββ isDeleted: boolean
β
βββ π messages (subcollection)
βββ {messageId} (document)
βββ id: string
βββ chatId: string
βββ senderId: string
βββ type: string
βββ text: string
βββ createdAt: timestamp
βββ editedAt: timestamp (optional)
βββ isDeleted: boolean
βββ replyToId: string (optional)
βββ replyToSenderId: string (optional)
βββ replyToSenderName: string (optional)
βββ replyToText: string (optional)
Security rules are defined in firestore.rules.
Important
The included rules are stricter than the default test-mode rules. They enforce that:
- Users can only write to their own profile
- Only chat participants can read/write chats and messages
- Messages can only be created (no editing or deleting from client)
Review and adjust the rules in firestore.rules to fit your needs before deploying.
This project requires a composite index for querying chats. The index configuration is defined in firestore.indexes.json.
| Collection | Fields | Query Scope |
|---|---|---|
chats |
participants (Array) + updatedAt (Descending) |
Collection |
Tip
If you skip deploying indexes, Firestore will show an error with a direct link to create the required index when the app first runs a query that needs it.
Deploy both rules and indexes at once:
firebase deploy --only firestore --project YOUR_PROJECT_IDOr deploy them individually if needed:
firebase deploy --only firestore:rules --project YOUR_PROJECT_ID
firebase deploy --only firestore:indexes --project YOUR_PROJECT_IDTip
If you skip this step, Firestore will show an error with a direct link to create the required index when the app first runs a query that needs it.
-
Via Firebase Console (Recommended):
- Open Firebase Console
- Select your project β Project Settings
- Add a Web app (if not already added)
- The Client ID will be auto-generated in Google Cloud Console
-
Manual Setup:
- Go to Google Cloud Console
- Navigate to APIs & Services β Credentials
- Create OAuth client ID β Select Web application
- Configure:
- Authorized JavaScript origins:
http://localhosthttp://localhost:5000https://your-domain.firebaseapp.com(production)
- Authorized redirect URIs:
https://your-domain.firebaseapp.com/__/auth/handler
- Authorized JavaScript origins:
- Copy the generated Client ID
The profiles table in Supabase is used to sync FCM tokens for notification delivery:
create table profiles (
id uuid references auth.users on delete cascade,
email text unique,
fcm_token text,
updated_at timestamp with time zone,
primary key (id)
);Talkest uses Supabase Edge Functions to trigger FCM v1.
- Service Account: Place your Firebase Service Account JSON in the Edge Function environment.
- Environment Variables: Set up the following in your Supabase project:
FIREBASE_SERVICE_ACCOUNT: Your JSON key.
- Deployment:
supabase functions deploy send-notification
Web (Development):
flutter run -d chrome \
--dart-define=GOOGLE_WEB_CLIENT_ID=YOUR_CLIENT_ID.apps.googleusercontent.com \
--dart-define=SUPABASE_ANON_KEY=YOUR_SUPABASE_ANON_KEYMobile (Android/iOS):
flutter run -d <device-id> \
--dart-define=SUPABASE_ANON_KEY=YOUR_SUPABASE_KEYWeb (Release)
flutter build web --release \
--dart-define=GOOGLE_WEB_CLIENT_ID=YOUR_WEB_ID.apps.googleusercontent.com \
--dart-define=SUPABASE_ANON_KEY=YOUR_SUPABASE_KEYImportant
Web builds require the Google Web Client ID for authentication.
Mobile (Release)
flutter build --release \
--dart-define=SUPABASE_ANON_KEY=YOUR_SUPABASE_KEYImportant
Mobile builds now require the SUPABASE_ANON_KEY to sync FCM tokens and send notifications.
Talkest supports an embedded chat widget mode, designed to be loaded inside an <iframe> on any website. This allows visitors to chat with a specific user directly from your page.
URL format:
https://your-talkest-deployment.com/?embed=1&targetUid=FIREBASE_USER_UID
Example iframe usage:
<iframe
src="https://khip01.github.io/talkest/?embed=1&targetUid=YOUR_FIREBASE_UID"
width="400"
height="600"
style="border: none; border-radius: 12px;"
allow="clipboard-read; clipboard-write"
></iframe>Parameters:
| Parameter | Required | Description |
|---|---|---|
embed |
Yes | Set to 1 to activate embedded mode |
targetUid |
Yes | The Firebase UID of the user to chat with |
Tip
You can find your Firebase UID in the Firebase Console β Authentication β Users tab.
In embed mode, the app will:
- Show a landing page with a sign-in prompt for unauthenticated visitors
- Automatically open a direct chat with the target user after sign-in
- Hide navigation elements like the FAB and profile access for a clean widget experience
Made with π€ by Khip01




