Engagement starter on iOS

The Engagement Starter is a compact, self-contained widget that invites readers into the
conversation for a piece of content. It picks its own layout based on what the conversation
actually has to show:

VariantWhen it rendersWhat it shows
DefaultNo poll and no featured commentHeader, title, description and a call-to-action button
Editor's pickThe conversation has a pinned or picked commentThe featured comment with its author, like/dislike/reply row, and the call to action
PollThe conversation has a poll and polls are enabled for the siteThe poll question, its options, and (after voting) results

A pinned comment takes precedence over an editor's pick, and a poll takes precedence over
both.

In the iOS SDK the widget is named Conversation Starter
(VFConversationStarterViewController), which is the same widget as the web Engagement
Starter.

Requires ViafouraCore 1.3.1 or newer.


Behaviour worth knowing before you integrate

  • It never creates a conversation. The widget reads the comment container without
    creating it, so rendering the Engagement Starter on an article that has never been
    commented on does not bring a conversation into existence. When the container does not
    exist yet, the default variant is shown.
  • It hides itself when there is nothing to say. If the conversation is hidden, or closed
    with zero comments, and there is no poll, the widget hides its content and reports a
    height of 0. Size the host view off the height delegate rather than a fixed height.
  • The call to action adapts to the comment count. With at least minimumCommentCount
    comments the button shows the count; with zero comments it invites the first comment;
    otherwise it drops the count. The default is
    VFConversationStarterDefaults.minimumCommentCount (5).
  • On the poll variant the call to action only appears once results are visible — that is,
    after the reader votes or once the poll is closed.
  • The dislike button on the featured comment is only rendered when dislikes are enabled
    for the site, and voting on a poll prompts login only when the site requires
    authentication to vote.
  • Analytics are on by default. The widget logs its own load, view and click events with a
    subtype of default, editor_pick or poll. The view event fires the first time the
    widget is actually on screen — when it is embedded in a scroll view, the SDK tracks that
    scroll view to decide when the widget becomes visible. To honour a reader's consent
    choice, call ViafouraSDK.setDataTrackingEnabled(false); nothing else needs to change.

UIKit

import ViafouraSDK

let starter = VFConversationStarterViewController.new(
    containerId: "YOUR_CONTAINER_ID",
    articleMetadata: VFArticleMetadata(
        url: articleURL,
        title: "Article title",
        subtitle: "Article subtitle",
        thumbnailUrl: thumbnailURL
    ),
    loginDelegate: self,
    settings: VFSettings(colors: VFColors(colorPrimary: .systemBlue)),
    title: nil,                 // optional override for the default variant's title
    description: nil,           // optional override for its description
    minimumCommentCount: 5,     // VFConversationStarterDefaults.minimumCommentCount
    syndicationKey: nil
)

starter.setTheme(theme: .light)
starter.setLayoutDelegate(layoutDelegate: self)
starter.setCustomUIDelegate(customUIDelegate: self)

addChild(starter)
view.addSubview(starter.view)
starter.didMove(toParent: self)

Pass a sectionUUID to the second new(...) overload if the content lives in a section
other than your site's default; otherwise the site UUID is used.

Actions

starter.setActionCallbacks { action in
    switch action {
    case .seeMoreCommentsPressed:
        // Reader tapped the call to action — open your comments screen
        break
    case .writeNewCommentPressed(let actionType):
        // Reader tapped "Reply" on the featured comment; actionType is .reply(content:)
        break
    case .openProfilePressed(let userUUID, let presentationType):
        // Reader tapped the featured comment's author
        break
    case .commentLiked(let contentUUID), .commentDisliked(let contentUUID):
        // Reader reacted to the featured comment
        break
    case .authPressed(let promptType):
        // Reader reacted or voted while logged out
        break
    default:
        break
    }
}

VFLoginDelegate.startLogin() is also called when a logged-out reader likes, dislikes or
votes, so present your login flow there.

Height

The widget reports its own height through VFLayoutDelegate, in points:

func containerHeightUpdated(viewController: VFUIViewController, height: CGFloat) {
    starterHeightConstraint.constant = height
}

The height is 0 whenever the widget hides itself, so a constraint driven by this callback
collapses the widget without leaving a gap.


SwiftUI

import ViafouraSDK

VFConversationStarterView(
    containerId: "YOUR_CONTAINER_ID",
    articleMetadata: articleMetadata,
    settings: settings,
    title: nil,
    description: nil,
    minimumCommentCount: 5,
    onLogin: { presentLogin() },
    onAction: { action in
        if case .seeMoreCommentsPressed = action {
            openComments()
        }
    },
    onHeightChange: { height in
        // Optional — the view already sizes itself when autoSize is true
    }
)

VFConversationStarterView sizes itself by default (autoSize: true) and follows the
environment colour scheme unless you pass an explicit theme:.


Refreshing

starter.reload()      // re-fetch the container, featured comment and poll
starter.reloadPoll()  // re-fetch only the poll, e.g. after a poll changes elsewhere

Styling

Colours, fonts and theme come from the VFSettings you pass in, and
setTheme(theme:) switches the theme at runtime.

For finer control, VFCustomUIDelegate hands you these views:

VFCustomizableView caseView
conversationStarterBackgroundViewThe widget's root view
conversationStarterHeaderLabelThe small header above the title
conversationStarterTitleLabelThe default variant's title
conversationStarterDescriptionLabelThe default variant's description
conversationStarterFeaturedCommentLabelThe featured comment's text
conversationStarterActionButtonThe call-to-action button
func customizeView(theme: VFTheme, view: VFCustomizableView) {
    if case .conversationStarterActionButton(let button) = view {
        button.layer.cornerRadius = 20
    }
}

Did this page help you?