name: apex-connect-api-chatter description: "Use when posting to a Chatter feed, creating feed comments, @mentioning users or groups, or rendering rich-text posts from Apex via the ConnectApi namespace. Trigger keywords: ConnectApi, FeedItem, Chatter post, @mention, rich text post, FeedElementCapabilities, link post. NOT for: email notifications (see apex-email-messaging), custom bell notifications (see apex-custom-notifications-from-apex), or Experience Cloud feed embeds (see community-feed-components)." category: apex salesforce-version: "Spring '25+" well-architected-pillars:
- Security
- Reliability triggers:
- "How do I post a Chatter comment with a file attachment from Apex?"
- "I want to @mention a user in a FeedItem I'm creating from a trigger"
- "My ConnectApi.ChatterFeeds.postFeedElement call works in UI tests but fails in @future context" tags:
- apex-connect-api-chatter
- apex-chatter-posting
- apex-connectapi
- apex-mentions inputs:
- "Feed parent Id (record, user, group) being posted to"
- "Post payload: text, mentions, links, file attachment"
- "Execution context (sync, trigger, async)" outputs:
- "ConnectApi-based Chatter post implementation"
- "Checker findings against unsupported async usage and unsafe input" dependencies: [] version: 1.0.0 author: Pranav Nagrecha updated: 2026-04-23
Apex Connect Api Chatter
Activate this skill when Apex needs to post to Chatter, reply to a feed item, or @mention a user programmatically. The ConnectApi namespace is the only supported way to produce rich-content posts (mentions, links, files, polls) — direct DML on FeedItem is limited and does NOT support mention rendering.
Before Starting
Gather this context before working on anything in this domain:
- Is Chatter enabled in the org?
ConnectApithrowsConnectApi.ConnectApiExceptionif disabled. - What's the execution context?
ConnectApihas strict restrictions in@futureand test methods. - What sort of post? Plain text, text-with-mentions, link, file attachment, poll, or announcement?
- Who's the author? Running user by default; can impersonate only via
ConnectApi.ChatterFeeds.postFeedElementparameters in limited cases.
Core Concepts
ConnectApi vs Direct DML On FeedItem
insert new FeedItem(...)works but produces plain text only. No mentions, no files, no polls.ConnectApi.ChatterFeeds.postFeedElement(...)supports the full post capability set (mentions, files, links, polls, announcements).- Rule: if the post has any rich content, use ConnectApi. Use direct DML only for the simplest text post where capabilities are not needed.
FeedItemInput + MessageBodyInput + MessageSegmentInput
Rich posts are assembled from segments:
TextSegmentInput— plain textMentionSegmentInput—@useror@groupLinkSegmentInput— inline URLHashtagSegmentInput—#topic
Segments are concatenated in order into a MessageBodyInput, which is wrapped in a FeedItemInput.
Test Context Restrictions
ConnectApimethods throw in synchronous test methods unlessTest.setMock(ConnectApi.ConnectApi.class, mock)or theSeeAllData=trueannotation is used.SeeAllData=trueis a code-smell in most orgs; prefer the mock framework.@futuremethods CAN callConnectApi, but the calls run as the user who enqueued (or the automated user in some contexts) — test this explicitly.
Feed Parent Id Types
Feeds hang off a parent record. Common parent types:
- User Ids (
005...) — user's personal feed - Group Ids (
0F9...) — Chatter group - Record Ids (
001...etc.) — any object with feed tracking enabled 'me'— shorthand for the running user
Common Patterns
Plain-Text Post With @Mention
When to use: A trigger or service needs to notify an owner by @mentioning them in a record feed.
How it works:
public static void postMentionToRecord(Id recordId, Id userToMention, String message) {
ConnectApi.FeedItemInput post = new ConnectApi.FeedItemInput();
ConnectApi.MessageBodyInput body = new ConnectApi.MessageBodyInput();
body.messageSegments = new List<ConnectApi.MessageSegmentInput>();
ConnectApi.MentionSegmentInput mention = new ConnectApi.MentionSegmentInput();
mention.id = userToMention;
body.messageSegments.add(mention);
ConnectApi.TextSegmentInput text = new ConnectApi.TextSegmentInput();
text.text = ' ' + message;
body.messageSegments.add(text);
post.body = body;
ConnectApi.ChatterFeeds.postFeedElement(Network.getNetworkId(), recordId, post);
}
Why not the alternative: insert new FeedItem(Body='@Jane ...') shows literal @Jane text — no notification fires, no link is rendered.
Post With File Attachment
When to use: Uploading a report PDF and posting it to a record feed in one go.
How it works:
ConnectApi.FeedItemInput input = new ConnectApi.FeedItemInput();
ConnectApi.MessageBodyInput body = new ConnectApi.MessageBodyInput();
body.messageSegments = new List<ConnectApi.MessageSegmentInput>{
new ConnectApi.TextSegmentInput()
};
((ConnectApi.TextSegmentInput) body.messageSegments[0]).text = 'See attached report.';
input.body = body;
ConnectApi.NewFileAttachmentInput file = new ConnectApi.NewFileAttachmentInput();
file.title = 'Weekly Report';
input.capabilities = new ConnectApi.FeedElementCapabilitiesInput();
input.capabilities.content = new ConnectApi.ContentCapabilityInput();
input.capabilities.content.title = file.title;
ConnectApi.BinaryInput binary = new ConnectApi.BinaryInput(
Blob.valueOf(pdfBytes), 'application/pdf', 'report.pdf');
ConnectApi.ChatterFeeds.postFeedElement(
Network.getNetworkId(), recordId, input, binary);
Decision Guidance
| Situation | Recommended Approach | Reason |
|---|---|---|
| Plain text post, no mentions | Either ConnectApi or DML | Choose by team convention |
| Text with @mention | ConnectApi MentionSegmentInput | DML produces literal text |
| Post + file attachment | ConnectApi with BinaryInput | No DML equivalent |
| Poll post | ConnectApi PollCapabilityInput | No DML equivalent |
| Scheduled reminder post | Queueable calling ConnectApi | Governor-safe |
| Bulk posts (100s) | Batch + ConnectApi per record | Respects limits per execution |
| Experience Cloud posts | Network.getNetworkId() arg | null posts to internal Chatter |
Recommended Workflow
- Confirm Chatter is enabled — feature check via
FeatureManagementor an admin confirm. - Identify feed parent — user, group, or record with feed tracking enabled.
- Build the
FeedItemInputby assembling message segments; handle null/empty text explicitly. - Decide sync vs async — post in the current transaction unless you need isolation; if async, write a governor-bounded Queueable.
- Write tests —
Test.setMock(ConnectApi.ConnectApi.class, ...)to avoid real feed writes; assert the payload shape. - Test Experience Cloud separately if posts must appear in a partner/customer community —
Network.getNetworkId()argument matters.
Review Checklist
- No literal
@usernamestrings in FeedItem.Body — mentions are alwaysMentionSegmentInput. -
Network.getNetworkId()(not hardcoded network Id) for community context. - Tests use
Test.setMock(ConnectApi.ConnectApi.class, ...). - ConnectApi call wrapped in try/catch of
ConnectApi.ConnectApiException. - Messages under Chatter's 10,000 char soft limit.
- File attachments under 2GB / org-specific limit.
Salesforce-Specific Gotchas
- Chatter off means ConnectApiException — orgs with Chatter disabled throw on every call; feature-flag the code.
FeedItemDML cannot render mentions —@Janeappears as literal text, no notification fires.ConnectApiin test requires mocks —SeeAllData=false(the default) blocks real Chatter calls; useTest.setMockor the call throws.- Network Id must be passed — omitting or using the wrong community Id posts to the wrong feed silently.
- Mentions require feed visibility — user must have access to the parent record; otherwise the mention is rendered but no notification fires.
- Feed tracking must be on — posting to a record whose object lacks feed tracking fails with a specific ConnectApiException.
- Polls cannot be edited after posting — only deleted and reposted.
- ConnectApi does NOT call triggers on FeedItem —
FeedItemtriggers fire on DML, but ConnectApi writes go through a separate path; relying on FeedItem triggers for ConnectApi posts is unreliable.
Output Artifacts
| Artifact | Description |
|---|---|
scripts/check_apex_connect_api_chatter.py | Scans for literal @ mentions in FeedItem DML, missing ConnectApi mocks in tests, and unsafe error handling |
templates/apex-connect-api-chatter-template.md | Work template for assembling FeedItemInput with mentions and attachments |
Related Skills
apex-custom-notifications-from-apex— bell notifications (different system from Chatter)apex-email-messaging— email outreach (Chatter is not email)apex-blob-and-content-version— managing files attached to Chatter posts