Community: in-app feed, comments and profiles
Everything is driven from Community in the sidebar, once you have picked the app concerned. Each community belongs to one app and one only.
Enabling it
Customise → General → Community enabled.
Enabling does three things at once, so you do not have to guess them:
- the feed becomes visible in the SDK
- a default group is created
- the Community product is enabled on your App ID
While it is off, the SDK shows a waiting screen and no content is served. That is the default: nobody wants an empty feed appearing in a production app on deployment day.
Groups
The tabs of your feed. A post belongs to exactly one group, which keeps the tabs readable and the counters honest.
| Setting | Effect |
|---|---|
| Name, emoji, description | What the member sees |
| Who can post | "Everyone" or "The team only" |
| Archive | Hidden in the app, its posts stay in the database |
"The team only" turns the group into a noticeboard: members read and comment, they do not post. That is the mechanism behind welcome groups of the "About…" kind.
The default group receives posts with no explicit group. It can be neither deleted nor archived - otherwise those posts would have nowhere to go. A group can only be deleted when empty; otherwise, archive it.
Posts
The table of everything published, by your team as well as by members. Filterable by group, status and full-text search.
Posting
A studio post carries the "team" badge and does not go through moderation: you do not have to pass your own filter. The configured maximum length applies to members, not to your announcements.
Options: pin to the top of the group, show or hide the team badge, schedule.
Scheduling
Set a future date: the post goes out automatically at that time (to the minute). A future date always implies scheduling, even if you ask to "publish now" - otherwise a post dated tomorrow would appear at the top of the feed today.
Creating in bulk
Up to 50 posts at once, to seed a community or roll out an editorial calendar. One block per post, the shared options at the top.
It is all or nothing: if one entry is rejected, none is created. A half published series would be more painful to recover from than a clean failure, because you would first have to work out where it stopped.
Statuses
| Status | Meaning |
|---|---|
| Published | Visible in the feed |
| Awaiting review | Held by moderation, visible only to its author |
| Scheduled | Will go out at its date |
| Draft | Will not go out until you decide |
| Removed | Removed by moderation, kept for audit |
Deleting or removing
Two different acts:
- Delete (Posts table) erases permanently, with comments and reactions. For content that should never have existed - personal data published by mistake, an erasure request.
- Remove (moderation queue) sets it to "Removed" and logs the decision. That is the act for sanctioning.
Members
Everyone who has opened the community. A profile is created the first time the feed opens, with no sign-up.
Editable inline:
- Role - member, moderator, admin
- Team badge - shows a badge under the nickname in the feed
You can edit neither the nickname nor the bio of a member. Moderating content is legitimate; rewriting someone's identity is not. Sanctions go through the Decision button, which logs them.
Moderation
Queue
Reports from members, enriched with an excerpt of the content concerned, its author and the number of reports on the same target - enough to decide without opening three screens.
A member reports a piece of content only once: otherwise the counter that triggers automatic hiding would be trivial to manipulate.
Decisions
A single route for every action, which guarantees that no decision escapes the log.
On content:
| Action | Effect |
|---|---|
| Leave online | Dismisses the reports, the content stays |
| Remove | Hidden for everyone, kept for audit |
| Restore | Undoes a removal |
On a profile:
| Action | Effect |
|---|---|
| Warn | Logged, no visible effect |
| Shadow ban | The member posts and sees their content, nobody else does. Never notified |
| Ban | Read only |
| Lift the sanction | Back to normal |
| Erase the profile | Nickname, bio and avatar erased (GDPR). Posts remain, signed with the name of the time |
Ban and shadow ban accept a duration; with no duration, the sanction is permanent. A temporary sanction is lifted automatically when the member returns.
The shadow ban is the only tool that does not announce itself. A banned member knows it and goes to complain elsewhere; a shadow banned member keeps talking into the void. Reserve it for cases where the noise is the problem.
Modes
Customise → Moderation.
| Mode | Behaviour |
|---|---|
| Off | Everything is published. Reports still arrive |
| Automatic | Every piece of content is evaluated before publication |
| Manual | Nothing is published without approval. Only sustainable at low volume |
In automatic mode, two thresholds between 0 and 1:
- above the review threshold, the content goes to the queue instead of being published;
- above the rejection threshold, it is rejected outright and the author knows.
Banned words are compared on whole words, ignoring case and accents. A match rejects the content without calling the classifier.
Automatic hiding after N reports sets the content aside pending arbitration. That is what lets the community defend itself overnight. Zero disables it.
If the classifier fails, the content is published. A community that rejects everything because a provider is down is broken in a far more visible way than an hour of unfiltered content. Reports remain the safety net.
Log
Every decision, human and automatic, with its reason. Never edited, never purged: it is what lets you answer "why was this member banned?" six months later.
Statistics
Every counter is shown with its value over the previous period of the same length. "240 posts" says nothing; "240 against 180" says everything.
Audience
Members, new members, active members, active per day, opens.
"Active members" counts distinct people who opened the community, not the number of opens.
Contribution
Posts, comments, reactions, views, and the participation rate: the share of active members who post or comment.
It is the metric that separates a community from a wall of announcements. An audience that climbs with a rate that collapses describes a community people watch without taking part in.
Views are unique per member: scrolling back over a post does not inflate the counter.
Health
Pending reports, reports over the period, removed content, banned members. These metrics are inverted on display - a rise is shown in red.
Retention
The share of each weekly cohort still active N weeks later. The colour intensity carries the information: you read a sagging curve at a glance.
It is the only indicator that says whether the community holds. An activity curve can climb purely because you are acquiring, while every cohort evaporates.
Leaderboards
Top contributors and most viewed posts, over the period and not cumulative. A leaderboard frozen on totals would reward the old-timers forever and hide who is carrying the community this month.
Customising
Four tabs, each saved independently: setting moderation does not overwrite the theme.
| Tab | Contents |
|---|---|
| General | Enabling, features, translation |
| Appearance | Colour, font, size, corner radius, light/dark theme, preview |
| Content | Maximum lengths, images per post, lines before "see more", flood protection |
| Moderation | Mode, thresholds, automatic hiding, rules, banned words |
Every change is picked up by the SDK on the next open, with no resubmission of the app.
Using your own font
In Appearance, choose "Custom" and enter the PostScript name of a font already bundled in your app - not the file name.
# Find the PostScript name of a font file
mdls -name com_apple_ats_name_postscript MyFont.ttf
If the SDK cannot find the font, it silently falls back to the system font: a missing font must not make the feed unreadable.
This setting is iOS only: on Android, "custom" and "rounded" fall back to the system default. Bundling a typeface in the SDK would weigh on every integrating app, including the ones that do not want it.
Instant translation
Content is translated into the reader's device language. The first reader of a language pays for the call to the translator, the following ones read the cache - that is what makes the feature sustainable.
The member can always go back to the original text.
Embedding the feed in your app
The feed is rendered natively by the SDK. Your app provides an entry point - a tab, a button - and the SDK draws the rest. Two prerequisites:
- The SDK is installed and
AppwinCore.configureis called at launch (AppwinCore.instance.configurein Dart). - The community is enabled, as described at the top of this page. Without that, the SDK renders a waiting screen and the calls get a 403.
SwiftUI - in a tab
import AppwinCommunity
TabView {
HomeView()
.tabItem { Label("Home", systemImage: "house") }
AppwinCommunity.communityView()
.tabItem { Label("Community", systemImage: "bubble.left.and.bubble.right") }
}
UIKit
let communityVC = AppwinCommunity.communityViewController()
communityVC.tabBarItem = UITabBarItem(
title: "Community",
image: UIImage(systemName: "bubble.left.and.bubble.right"),
tag: 1
)
tabBarController.viewControllers = [homeVC, communityVC, profileVC]
Modal
AppwinCommunity.presentCommunity()
What the member can do
Depending on what is enabled in the dashboard:
- read the feed, filter by group, pull to refresh
- post, edit and delete their own content
- comment, reply to a comment (one level only)
- react to posts and comments
- view profiles, edit their own, go back to anonymous
- report a post, a comment or a profile
- read in their own language if translation is on
Each of these has a switch on the studio side. A feature that is turned off disappears from the interface; it is not greyed out.
Localisation
The SDK's labels are resolved in your app's resources, not in the module's. You can therefore translate or reword any label without waiting for a release from us.
Add an AppwinCommunity.strings to your project:
"community.new_post" = "Share something";
"community.like" = "Like";
"community.comments" = "Reactions";
The keys are listed in CommunityStrings.swift.
With no resource provided, the SDK uses its English defaults - never a raw key on screen. Two uses:
- translating into a language we do not ship yet
- rewording a label that does not match your tone
Troubleshooting
| Symptom | Likely cause |
|---|---|
| "Coming soon" screen | Community disabled in the dashboard |
| 403 on every call | Community product not enabled on the App ID - re-enable it from Customise |
| Empty feed with no error | No posts; publish from the dashboard to seed it |
| The feed does not scroll (Flutter) | A parent widget intercepts the gesture |
| Native error screen | configure not called before the view is shown |
| iOS build fails | Deployment target below iOS 16 |
Next
- Installation - installing and initialising the SDK
- Identity - anonymous, signed in, shared across products
- Community SDK API - the endpoints
- Support - the other in-app surface