gvl_comments 1.2.0 copy "gvl_comments: ^1.2.0" to clipboard
gvl_comments: ^1.2.0 copied to clipboard

Drop-in comments widget and comment section for Flutter, with threaded replies, reactions and moderation. Managed backend included, no Firebase setup, just an install key.

gvl_comments — Add comments to any Flutter app #

GVL Comments Flutter SDK demo — threaded replies, reactions, instant posting and moderation

pub.dev pub points license flutter

Drop-in comment section for Flutter: threaded replies, reactions, moderation and instant (optimistic) posting, with no backend to build. Powered by GoodVibesLab Cloud.

  • Android & iOS
  • Free plan: 1,000 comments/month, AI moderation included, no credit card (pricing)
  • Data hosted in the EU (Stockholm)

Why gvl_comments? #

What you get What you skip
Comments UI (list + composer) Designing a database schema
Threaded replies (depth 2) Writing security rules / RLS
6 emoji reactions Building pagination & cursor logic
AI + user report moderation Rate-limiting and abuse prevention
Cursor-based pagination Token management
Material 3 theming (5 presets) Maintaining backend infrastructure

One install key, zero backend code.


Quick start #

1. Get an install key #

  1. Sign up at goodvibeslab.cloud (free) and create a project.
  2. In the project's Platforms card, register your app: Android Package name (applicationId) and/or iOS Bundle ID.
  3. Click Add key and copy the install key (cmt_live_…).

Install keys only work for the apps registered on the project. Skipping step 2 makes the first token request fail with api_key_not_bound_to_app.

2. Install #

# pubspec.yaml
dependencies:
  gvl_comments: ^1.2.0

3. Initialize #

import 'package:gvl_comments/gvl_comments.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  await CommentsKit.initialize(
    installKey: const String.fromEnvironment('GVL_INSTALL_KEY'),
  );

  runApp(const MyApp());
}
flutter run --dart-define=GVL_INSTALL_KEY="cmt_live_xxx"

4. Add the widget #

CommentsList(
  threadKey: 'post:550e8400-e29b-41d4-a716-446655440000',
  user: UserProfile(id: 'user-1', name: 'Alice'),
)

That's it. Comments load, users post, reactions work — all out of the box.

Using your own auth #

Pass the signed-in user from whatever auth you already use. id must be stable for that user (it's how comments, reactions and reports are attributed):

// Firebase Auth
final u = FirebaseAuth.instance.currentUser!;
final user = UserProfile(id: u.uid, name: u.displayName, avatarUrl: u.photoURL);

// Supabase Auth
final s = Supabase.instance.client.auth.currentUser!;
final user = UserProfile(id: s.id, name: s.userMetadata?['name']);

Features #

CommentsList #

Full-featured comment thread with built-in composer, pagination, and optimistic posting.

CommentsList(
  threadKey: 'article:01HV9ZJ7Q4X2M0YB8K9E',
  user: currentUser,
  newestAtBottom: false,        // feed mode (default) or chat mode
  limit: 30,                    // comments per page (1–100)
  reactionsEnabled: true,       // emoji reaction bar
  shrinkWrap: true,             // embed inside a parent scrollable
  header: MyArticleCard(),      // scrolls with comments
  theme: GvlCommentsThemeData.bubble(context),
)

CommentCount #

Lightweight counter — no full list load.

CommentCount(
  threadKey: 'post:550e8400-e29b-41d4-a716-446655440000',
  user: currentUser,
  builder: (context, count, refresh) => Text('$count comments'),
)

TopComment #

Display the most-engaged comment (highest reactions) as a preview.

TopComment(
  threadKey: 'post:550e8400-e29b-41d4-a716-446655440000',
  user: currentUser,
  onTap: () => Navigator.push(/* full thread */),
)

Batch prefetch #

Avoid N+1 in lists — prefetch counts and top comments for multiple threads at once.

await CommentsKit.I().prefetchThreads(
  posts.map((p) => 'post:${p.id}').toList(),  // e.g. UUIDs from your DB
  user: currentUser,
);
// CommentCount and TopComment now read from cache

Theming #

Five built-in presets, all Material 3 compatible:

GvlCommentsThemeData.defaults(context)  // adapts to app theme
GvlCommentsThemeData.neutral(context)   // minimal, clean
GvlCommentsThemeData.compact(context)   // dense, for dashboards
GvlCommentsThemeData.card(context)      // elevated cards
GvlCommentsThemeData.bubble(context)    // chat-style bubbles

Full control via properties:

GvlCommentsThemeData(
  bubbleColor: Colors.blue.shade50,
  avatarSize: 32,
  spacing: 12,
  bubbleRadius: BorderRadius.circular(16),
  authorStyle: TextStyle(fontWeight: FontWeight.bold),
)

Or use Theme.of(context).extension<GvlCommentsThemeData>() for app-wide styling.


Reactions #

Six reactions: like, love, laugh, wow, sad, angry.

  • Tap to toggle the default reaction (like)
  • Long-press to open the reaction picker
  • Disable per widget: reactionsEnabled: false

Moderation #

Comments pass through a moderation pipeline:

Status Behavior
approved Visible normally
pending Visible to author, placeholder for others when flagged
rejected Replaced by "This comment has been moderated"
  • User reports — from the ⋯ menu on each comment, with a confirmation step; duplicate-safe
  • AI moderation — automatic flagging, on by default on every plan (free included)
  • Configure thresholds and sensitivity from the dashboard

Programmatic API #

Full control beyond the widget:

final kit = CommentsKit.I();

// Thread keys must be high-entropy (UUID/ULID/Firestore doc id, 20+ chars).
const threadKey = 'post:3f2b8c1e-9a4d-4e7f-b2c6-1d8e5a7f9b30';

// List with pagination
final page = await kit.listPage(threadKey, user: user);
final comments = page.items;
if (page.hasMore) {
  final next = await kit.listPage(threadKey, user: user, cursor: page.nextCursor);
}

// Post
final comment = await kit.post(
  threadKey: threadKey,
  body: 'Hello!',
  user: user,
  parentId: parentComment.id,  // optional, for replies
);

// React
await kit.setCommentReaction(
  commentId: comment.id,
  reaction: Reaction.love.id,  // or null to remove
  user: user,
);

// Report
final isDuplicate = await kit.report(commentId: id, user: user);

// User identity (tokens are per user: a user switch is detected
// automatically; call invalidateToken() on logout to drop cached data)
await kit.identify(newUser);
kit.invalidateToken();

Builder hooks #

Override any part of the UI:

Builder Controls
commentItemBuilder Entire comment row
avatarBuilder Avatar widget
sendButtonBuilder Send button
composerBuilder Full input area
separatorBuilder Dividers between comments
loadMoreButtonBuilder Pagination button

Thread keys #

Thread keys identify comment threads. They must be:

  • 20+ characters long
  • High-entropy (UUID, ULID, Firestore doc ID)
  • Characters: a-zA-Z0-9:_-.
post:550e8400-e29b-41d4-a716-446655440000   ✅
article:01HV9ZJ7Q4X2M0YB8K9E               ✅
post-123                                     ❌ guessable

No pre-creation needed — threads are resolved server-side on first use.


Webhooks #

Subscribe to events from the dashboard:

Event Trigger
comment.created New comment posted
comment.replied Reply to existing comment
comment.liked Reaction added
comment.mentioned User mentioned in flattened reply

Payloads are signed with HMAC-SHA256. See the webhook docs for verification examples.


Security #

  • Short-lived JWTs — tokens expire after 1 hour
  • App binding — lock install keys to Android SHA-256 / iOS Team ID
  • Rate limiting — per IP, per user, per thread
  • Row-Level Security — tenant-isolated data, no cross-project access
  • 15s request timeout — prevents indefinite hangs

Localization #

Register the SDK's localization delegates in your MaterialApp:

MaterialApp(
  localizationsDelegates: GvlCommentsL10n.localizationsDelegates,
  supportedLocales: GvlCommentsL10n.supportedLocales,
)

Ships with 5 locales: English, French, Spanish, German, and Portuguese. All UI strings (timestamps, errors, hints, reaction labels) go through the l10n system.


Logging #

await CommentsKit.initialize(
  installKey: key,
  logLevel: CommentsLogLevel.trace,  // off | error | info | debug | trace
);

Defaults to error in release, debug in debug mode. Sensitive values (keys, tokens) are redacted.


FAQ #

Do I need my own backend or database? No. Comments, reactions, reports and moderation are stored and served by GoodVibesLab Cloud. You only ship the SDK and an install key.

Are new comments pushed in real time? No. Your own comments appear instantly (optimistic UI), and other people's comments show up on pull-to-refresh or when the thread is reopened.

Does it work offline? No. Loading and posting need a network connection. A failed post keeps the user's text and offers a retry.

Which platforms are supported? Android and iOS. Web and desktop are not supported yet.

Where is the data stored? In the EU (Stockholm). Each account's data is isolated by row-level security.

Can I restyle or replace the UI? Yes: use a theme preset, GvlCommentsThemeData properties, or the builder hooks to replace any part (item, avatar, composer, send button…).


Requirements #

Minimum
Flutter 3.19
Dart 3.3
iOS 13.0
Android API 24

Example app #

git clone https://github.com/GoodVibesLab/gvl_comments.git
cd gvl_comments/example
flutter run

Runs with a built-in demo key. Shows posting, reactions, theming, dark mode, and guest identity.


  • Dashboard — create projects, install keys, configure moderation
  • Documentation — full API reference and guides
  • Issues — bug reports and feature requests
  • Contact — support

License #

Commercial license. Included with all GoodVibesLab plans (free tier available).

2
likes
140
points
83
downloads
screenshot

Documentation

Documentation
API reference

Publisher

verified publishergoodvibeslab.cloud

Weekly Downloads

Drop-in comments widget and comment section for Flutter, with threaded replies, reactions and moderation. Managed backend included, no Firebase setup, just an install key.

Homepage
Repository (GitHub)
View/report issues

Topics

#comments #comment-section #moderation #reactions #widget

License

unknown (license)

Dependencies

crypto, flutter, flutter_localizations, http, intl, meta, package_info_plus, url_launcher

More

Packages that depend on gvl_comments

Packages that implement gvl_comments