public final class Invites

  1. Object
  2. Invites

Invite a friend, and follow the invitation through to what it caused.

Mint an invite, share it, and on the friend’s device recover the invite that produced the install. Once attribution resolves it is written as persistent analytics dimensions, so every later event – including the purchase event the framework already emits – carries the campaign and the referrer, and revenue per campaign comes out of the reports you have.

Sending

Invite invite = Invites.create(InviteRequest.create()
        .campaign("spring")
        .channel("share_sheet")
        .build());
Invites.share(invite, "Come and try this with me");

create returns immediately and works with no network, so the share sheet never waits on a server. Registration with the link service is retried in the background.

Receiving

Invites.setInviteListener(new InviteListener() {
    public void inviteReceived(InviteAttribution attribution) {
        // attribution.getCode(), getCampaign(), getPayload()
    }

    public void attributionUnavailable(String reason) {
    }
});
Invites.checkForInvite();

Call checkForInvite from your start() method. It is a pull rather than a callback on purpose: Android delivers a link by replacing the activity intent and iOS by setting a property, and reading the launch argument is the one path that behaves the same on both.

Everything reported here is gated on the analytics consent category of Analytics, and nothing is transmitted until consent is granted.

One thing does happen before consent: on first launch a coarse device profile – operating system version, hardware model, language, screen size – is written to local storage so that a deferred match is still possible once consent arrives. It is never transmitted while consent is withheld, and it is deleted outright if consent is refused. There is no alternative that also works, because the window in which a deferred match can be made closes within the hour, long before a typical consent prompt is answered. setAttributionWindow with 0 switches deferred attribution off entirely.

How exact the answer is

InviteAttribution.getMatchType says how the attribution was made. MATCH_DIRECT and MATCH_REFERRER are exact. MATCH_FINGERPRINT is a statistical match made on the server, used where the platform’s store carries no referrer, and it is occasionally wrong – check InviteAttribution.getConfidence and do not pay a referral bounty on it without saying so.

Fields

public static final int STATE_NONE = 0Nothing has been attributed and nothing is outstanding.
public static final int STATE_PENDING = 1An invite is being resolved; the answer has not arrived yet.
public static final int STATE_RESOLVED = 2This install has been attributed to an invite.
public static final int STATE_NONE_FOUND = 3No invite will be attributed to this install.
public static final int STATE_DECLINED = 4Attribution was abandoned because analytics consent was refused.
public static final String MATCH_DIRECT = "direct"The link opened an application that was already installed.
public static final String MATCH_REFERRER = "referrer"The invite code made the whole trip through the application store and came back verbatim.
public static final String MATCH_FINGERPRINT = "fingerprint"The server matched this install to a click statistically, because the platform’s store carries no referrer.
public static final String REASON_NO_MATCH = "no_match"No invite matched.
public static final String REASON_EXPIRED = "expired"The attribution window closed before an answer arrived.
public static final String REASON_CONSENT_DENIED = "consent_denied"Analytics consent was refused, so attribution was abandoned.
public static final String REASON_UNSUPPORTED = "unsupported"This platform cannot recover a deferred invite.
public static final String CATEGORY = "referral"The analytics category every invite event is reported under.
public static final String DIMENSION_CODE = "cn1_invite_code"Dimension carrying the matched invite code.
public static final String DIMENSION_CAMPAIGN = "cn1_campaign"Dimension carrying the campaign the invite belonged to.
public static final String DIMENSION_CHANNEL = "cn1_channel"Dimension carrying the channel the invite was sent through.
public static final String DIMENSION_MATCH = "cn1_invite_match"Dimension carrying how the attribution was made.
public static final long DEFAULT_ATTRIBUTION_WINDOW = 604800000LThe default attribution window: how long after a first launch a deferred invite may still be resolved.

Methods

public static void registerInstallReferrerSource(InstallReferrerSource source)Registers the platform hook that reads the application store’s install referrer.
public static Invite create(InviteRequest request)Mints an invite and returns it immediately.
public static void share(Invite invite, String message)Shares an invite through the native share sheet.
public static void share(Invite invite, String message, Rectangle sourceRect, ShareResultListener resultListener)Shares an invite through the native share sheet and reports the outcome.
public static void reportShareResult(Invite invite, ShareResult result)Reports the outcome of a share your application performed itself, rather than through share.
public static void setInviteListener(InviteListener l)Registers the listener that receives the invite behind this install.
public static InviteListener getInviteListener()The registered listener, or null.
public static boolean checkForInvite()Looks for an invite: first in the launch argument, then, when this looks like a fresh install, by asking the link service.
public static boolean handleUrl(String url)Offers a url to the invite machinery directly, for applications that consume the launch argument themselves or route it through com.codename1.router.
public static InviteAttribution getAttribution()The attribution for this install, or null when there is none yet.
public static int getState()Where attribution has got to: one of the STATE_ constants.
public static void conversion(String action)Reports that the invited user reached the outcome the invite existed for – signed up, joined the room, completed onboarding.
public static void conversion(String action, double value, String currency)Reports a conversion carrying a value, so revenue can be attributed to the campaign and the referrer.
public static void setLinkBase(String url)Points the invite machinery at a different link service.
public static String getLinkBase()The link service base address in use.
public static void setAttributionWindow(long millis)How long after a first launch a deferred invite may still be resolved.
public static long getAttributionWindow()The attribution window in milliseconds.
public static void setReattribution(boolean value)Whether a later invite replaces an earlier attribution.
public static boolean isReattribution()Whether last touch attribution is enabled.
public static void flush()Retries anything queued: unregistered invites, and an outstanding deferred match.
public static void reset()Forgets every trace of invite attribution on this device: the pending fingerprint, the resolved attribution and the referral dimensions.
public static boolean isRegistered(Invite invite)Whether the link service has acknowledged this invite.

Inherited methods

Field details

STATE_NONE

public static final int STATE_NONE = 0
Nothing has been attributed and nothing is outstanding.

STATE_PENDING

public static final int STATE_PENDING = 1
An invite is being resolved; the answer has not arrived yet.

STATE_RESOLVED

public static final int STATE_RESOLVED = 2
This install has been attributed to an invite.

STATE_NONE_FOUND

public static final int STATE_NONE_FOUND = 3
No invite will be attributed to this install.

STATE_DECLINED

public static final int STATE_DECLINED = 4
Attribution was abandoned because analytics consent was refused.

MATCH_DIRECT

public static final String MATCH_DIRECT = "direct"
The link opened an application that was already installed. Exact.

MATCH_REFERRER

public static final String MATCH_REFERRER = "referrer"
The invite code made the whole trip through the application store and came back verbatim. Exact.

MATCH_FINGERPRINT

public static final String MATCH_FINGERPRINT = "fingerprint"
The server matched this install to a click statistically, because the platform’s store carries no referrer. Not exact.

REASON_NO_MATCH

public static final String REASON_NO_MATCH = "no_match"
No invite matched. The ordinary outcome for an uninvited install.

REASON_EXPIRED

public static final String REASON_EXPIRED = "expired"
The attribution window closed before an answer arrived.

REASON_UNSUPPORTED

public static final String REASON_UNSUPPORTED = "unsupported"
This platform cannot recover a deferred invite.

CATEGORY

public static final String CATEGORY = "referral"
The analytics category every invite event is reported under.

DIMENSION_CODE

public static final String DIMENSION_CODE = "cn1_invite_code"
Dimension carrying the matched invite code.

DIMENSION_CAMPAIGN

public static final String DIMENSION_CAMPAIGN = "cn1_campaign"
Dimension carrying the campaign the invite belonged to.

DIMENSION_CHANNEL

public static final String DIMENSION_CHANNEL = "cn1_channel"
Dimension carrying the channel the invite was sent through.

DIMENSION_MATCH

public static final String DIMENSION_MATCH = "cn1_invite_match"
Dimension carrying how the attribution was made.

DEFAULT_ATTRIBUTION_WINDOW

public static final long DEFAULT_ATTRIBUTION_WINDOW = 604800000L
The default attribution window: how long after a first launch a deferred invite may still be resolved.

Method details

registerInstallReferrerSource

public static void registerInstallReferrerSource(InstallReferrerSource source)
Registers the platform hook that reads the application store’s install referrer. The Codename One build calls this before the application starts on platforms that have one; an application does not.

Parameters

source InstallReferrerSource
the platform source, or null to remove it

create

public static Invite create(InviteRequest request)

Mints an invite and returns it immediately.

This never blocks and never fails for want of a network. The code is generated on the device, so Invite.getUrl is usable at once; registration with the link service is queued and retried until it lands. A link clicked before that registration arrives is still attributed, because the server records the click against the code and joins it when the registration turns up.

Parameters

request InviteRequest
what to mint, must not be null

Returns

the invite, never null

share

public static void share(Invite invite, String message)
Shares an invite through the native share sheet.

Parameters

invite Invite
the invite to share, must not be null
message String
text placed before the link, or null for the link alone

share

public static void share(Invite invite, String message, Rectangle sourceRect, ShareResultListener resultListener)

Shares an invite through the native share sheet and reports the outcome.

The invite funnel’s invite_shared event is emitted from here, and only when the platform confirms the user actually shared – a dismissed sheet reports invite_share_dismissed instead. That is what makes the “shared” number a measurement rather than an assumption.

Parameters

invite Invite
the invite to share, must not be null
message String
text placed before the link, or null for the link alone
sourceRect Rectangle
popover anchor hint, may be null
resultListener ShareResultListener
receives the share outcome, may be null

reportShareResult

public static void reportShareResult(Invite invite, ShareResult result)

Reports the outcome of a share your application performed itself, rather than through share. Use this when the invite goes out through your own user interface – a contact picker, a message composer, a copy-link button – so the funnel still records whether it was really sent.

invite_shared is emitted only when result says the user actually shared; a dismissed sheet reports invite_share_dismissed instead. Calling this is optional and calling it twice for one share double counts, so call it once, from the share callback.

Parameters

invite Invite
the invite that was shared, must not be null
result ShareResult
the outcome the platform reported, may be null

setInviteListener

public static void setInviteListener(InviteListener l)

Registers the listener that receives the invite behind this install.

An answer that arrived before the listener was registered – which happens routinely on a cold launch from a link, because the platform delivers the link before the application starts – is delivered as soon as this is called.

Parameters

l InviteListener
the listener, or null to remove it

getInviteListener

public static InviteListener getInviteListener()
The registered listener, or null.

Returns

the listener

checkForInvite

public static boolean checkForInvite()

Looks for an invite: first in the launch argument, then, when this looks like a fresh install, by asking the link service.

Safe and cheap to call on every start; it will not attribute twice and will not report twice.

Returns

true when the launch argument carried an invite link

handleUrl

public static boolean handleUrl(String url)
Offers a url to the invite machinery directly, for applications that consume the launch argument themselves or route it through com.codename1.router.

Parameters

url String
the url to inspect, may be null

Returns

true when the url carried an invite code

getAttribution

public static InviteAttribution getAttribution()
The attribution for this install, or null when there is none yet.

Returns

the attribution

getState

public static int getState()
Where attribution has got to: one of the STATE_ constants.

Returns

the current state

conversion

public static void conversion(String action)
Reports that the invited user reached the outcome the invite existed for – signed up, joined the room, completed onboarding. No-op unless this install was attributed.

Parameters

action String
what the user did

conversion

public static void conversion(String action, double value, String currency)
Reports a conversion carrying a value, so revenue can be attributed to the campaign and the referrer. No-op unless this install was attributed.

Parameters

action String
what the user did
value double
the value of the conversion
currency String
the currency code, or null

setLinkBase

public static void setLinkBase(String url)
Points the invite machinery at a different link service. Defaults to the Codename One cloud, honouring the cloudServerURL display property.

Parameters

url String
the base address, with no trailing path

getLinkBase

public static String getLinkBase()
The link service base address in use.

Returns

the base address, never null

setAttributionWindow

public static void setAttributionWindow(long millis)
How long after a first launch a deferred invite may still be resolved. Clamped to at most 30 days. Zero switches deferred attribution off, which is the supported way to ship without the statistical match.

Parameters

millis long
the window in milliseconds

getAttributionWindow

public static long getAttributionWindow()
The attribution window in milliseconds.

Returns

the window

setReattribution

public static void setReattribution(boolean value)
Whether a later invite replaces an earlier attribution. Off by default: first touch stands, so a user’s cohort does not change underneath the reports.

Parameters

value boolean
true for last touch

isReattribution

public static boolean isReattribution()
Whether last touch attribution is enabled.

Returns

true when a later invite replaces an earlier one

flush

public static void flush()
Retries anything queued: unregistered invites, and an outstanding deferred match. Called for you on the paths that matter; exposed for an application that knows it has just regained connectivity.

reset

public static void reset()

Forgets every trace of invite attribution on this device: the pending fingerprint, the resolved attribution and the referral dimensions.

Analytics.resetClientId triggers this for you, because an erasure that left the referral dimensions behind would re-link the fresh identity to the same inviter.

isRegistered

public static boolean isRegistered(Invite invite)

Whether the link service has acknowledged this invite.

An unacknowledged invite is still shareable and still attributes – registration is retried until it lands – so this is a diagnostic rather than a gate.

Parameters

invite Invite
the invite to ask about, may be null

Returns

true once the server has acknowledged it