[draft] snip-0006
engagement-based zapping
Abstract
This proposal describes an opt-in feature allowing users to automatically zap the content they engage, thereby enabling zero-effort, engagement-based zapping.
Motivation
As a multi-sided marketplace, Stacker News (SN) thrives given a healthy ratio of quality creators to discerning and active spenders. A creator is motivated to post content on SN if they can expect reasonable compensation in proportion to the quality of their posts. Correspondingly, spenders are motivated to consume and reward content on SN if a sufficient number of creators post enough quality content. The more content of sufficient quality, the more likely a spender will engage and return. The more spenders rewarding at a sufficient level, the more likely a creator will post and return. While a single click to zap sets an upper bound on the effort a spender takes to reward creators, the programmability of Lightning enables engagement-based spending thereby reducing the effort to zero1.
Among the capabilities of an “internet money” is the ability to extend usage-based2 business models across the entire digital economy. As examples, Fountain.fm3 allows podcast listeners to compensate creators per minute listened, and SuredBits4 sold a feed of historic crypto prices on a pay-per-feed-item basis. The advantage of a usage-based business model for a community like SN is an increased flow of capital (strongly correlated with marketplace growth), thereby incentivizing more creation, thereby increasing the likelihood of active engagement, and so contributing to a self-reinforcing network effect increasing overall market health5.
The aim of this
snip
is to pump such a network effect and thereby contribute to the growth of SN6.Discussion
The essence of engagement-based zapping (EBZ) is that as a user engages with content on SN, each unit of content engaged will be zapped some reward after a settlement delay until an allocated EBZ budget is depleted. For example, in the simplest case, the user's
zap default
(as defined in their settings) could be zapped instantly (a settlement delay of 0) until they run out of sats (i.e. their EBZ budget is the entirety of their remaining balance).While suitable as an mvp, there are a few downsides to this simple EBZ model. First, users may want to set aside only a portion of their total sats for EBZ. Second, a fixed size reward combined with instant settlement does not allow a user to zap content as a function of the "amount" they engaged.
Something that could be interesting would be for the amount of time you spend on the post.
- Ben Carman7
Time is money. How could we enable EBZ as a function of the time spent engaging? We need to:
- effectively measure engagement
- delay settlement in order to accumulate engagements
- sort accumulated engagements by engagement amount
- distribute the budget across the content engaged as a function of the sort
Let's take each in turn.
Measuring Engagement
The two units of content on SN are posts and comments. The two main post types are discussions and links6. Users engage with posts and comments through one or more of zapping, reading, commenting, and navigating.
Users can engage with any post type by commenting. Additionally, discussion posts can be engaged through reading and link posts engaged by navigating. Moreover, comments can be engaged themselves by commenting (i.e. replying), and both posts and comments can be engaged through zapping. This taxonomy of content type and engagement type can be captured in the following table.
Engagement | Discussion Posts | Link Posts | Comments |
---|---|---|---|
zap | X | X | X |
read | X | ||
comment | X | X | X |
navigate | X |
The first step in enabling engagement-based zapping is to record which content a user enages. This requires specifying a measure for whether a user has engaged a unit of content or not. We propose two kinds of engagement measures: discrete and continuous.
Discrete Engagement Measures
To measure engagement discretely, we specify a predicate that takes as parameters the content engaged, the type of engagement, relevant context and return true or false.
The following is a table of discrete engagement measures for each engaggement type.
Engagement Type | Predicate |
---|---|
zap | the user zapped >0 sats |
read | the user visited the post for >0 seconds |
comment | the user commented >0 chars to a post or comment |
navigate | the user clicked on the link |
Since engagement is a boolean value given a disrete measure, there is no way to compare a user's engagement across content to determine which content they engaged with more. Instead, we need to introduce continuous engagement measures.
Continuous Engagement Measures
We can easily extend our discrete engagement measures to continuous ones by transforming our predicates into time valued functions.
Engagement Type | Measure |
---|---|
zap | the number of sats zapped times a time weight |
read | the number of seconds a user spent on a post |
comment | the number of seconds a user spent writing |
navigate | the number of seconds a user spent offsite |
As time valued functions, our measures now allow us to compare whether, say, a user engaged a post they read more than they engaged a comment they replied to. The downside of continuous measures is the complexity of implementation. Naive ways of tracking time can easily lead to pathaological results. Let's discuss some less-than-naive implmentations of engagement for the above types.
zap
Whether we should auto-zap based on zapping seems like a user preference that many would not opt-in to. If they did, the simplest implementation would be to weight each sat zapped by a single millisecond. Zaps would likely always rank low compared to other forms of engagement.
read
Starting a timer when a user opens a discussion post and measuring the time spent on the page is too naive since a page left open when a user is afk would count as high engagement. Instead, the time at which the post was opened should be tracked and a timer set whose moment of expiry represents the end of engagement. The end-of-engagement timer would be debounced by any scroll events. A suitable delay for the timer could be determined by the total number of characters on screen - as determined by the intersection observer api8 - divided by the average characters readable in a minute9.
Once the end-of-engagement timer expires, if the user begins scrolling again the measurement can be resumed and added to the total time engaged.
comment
The timestamp of the first keypress should be noted and the timestamp of the most recent keypress updated as the comment is typed. Once the comment is submitted, the time of the final keypress minus the time of the first keypress represents the total engagement time.
navigate
Perhaps the hardest of all the engagement types to track, a timestamp could be stored if a user clicks the link and the page goes out focus and then another timestamp taken once the page comes back into focus. The difference between the two could be treated as representing the time spent engaging the link but this seems too naive. Navigation engagement could also be represented by a constant amount of time.
Engagement Tracking
State concerning the current EBZ period should be tracked, including each unit of engagement over the EBZ period.
Aggregate Engagement
At the end of the EBZ period, all engagement amounts related to the same unit of content should be summed together to represent a user's total engagement with a unit of content.
Sorting Engagement
Each unit of content engaged should be sorted by a user's total engagement, thereby ordering all units of content engaged in the EBZ period from greatest to least engaged.
Filtering Engagement
Users could specify whether to distribute their EBZ budget across all content engaged or simply the top
n
engaged contents.Reward Functions
Finally, the entire EBZ budget can be allocated according to a curve. For example, a
constant
disbursement would distribute the budget evenly to all qualifying contents. A normalized linear
disburesement would allocate most of the reward to the most engaged content and then linearly reduce the reward for subsequent contents. A normalized inverse logarithmic
(steeply down and to the right) or normalized reflected logarithmic
(shallowly down and to the right) would strongly concentrate rewards with the first or the first few most engaged contents and reduce subsequent rewards substantially.example normalized inverse logarithmic reward function
import { payout } from './payout' async function normedInverseLogRewards(budget = 1, contents = []) { const norm = contents.reduce((norm, _, i) => norm + (1 / Math.log(i + 2)), 0) const disbursements = contents.map((content, i) => [content, (budget / norm) / Math.log(i + 2)]) for (const [content, disbursement] of disbursements) await payout(content, disbursement) }
UX
Settings
Users should opt-in to EBZ from their settings.
Users should be able to set the size of their EBZ budget in sats, initially 10 times their default zap amount.
Users should be able to set the amount of sats zapped per discrete engagement, initially set to their default zap amount.
Users should be able to set the period at which their EBZ budget refreshes, initially set to daily.
Users should be able to set whether manually zapped sats should count against their EBZ budget, initially set to true.
Comments
If EBZ is enabled, when a user comments there should be an option to turn EBZ off for that particular comment.
Notes
Footnotes
-
or more accurately, shifting the effort to acquiring sats and configuring your auto-spend ↩
-
usage of SN amounts to engagement of various kinds ↩
-
with SN’s sybil resistance (pay-to-post) acting as a control on junk (click-bait) content seeking to drain liquidity[&6]: This
snip
can be expanded in the future to cover polls, bounties, and jobs ↩