When I added share analytics, the metric name itself could suggest an overly simple design: there is a Share action, so everything related to a shared link could be counted in one place.
But there are actually two different events.
The first happens when a user clicks Share or Copy Link. The second happens later if someone opens the shared link.
These events may be causally related, but they are not the same action.
First Event: the User Clicked Share
Time: 10:15 User A | +-- opens article | +-- clicks Share | +-- chooses Copy Link | vShare action recordedThis is an interface interaction event.
We know which content was shared, which channel or action was used, and when it happened.
But we know nothing about the outcome yet. The link may have been copied and never sent. It may have been sent in a private chat. It may have been sent to ten people.
That is why a Share action is not a visit.
Second Event: Another Person Opened the Shared Link
Time: 10:47 User B | +-- receives shared link | +-- opens it | vShared-link visit recordedThis event happens later and often on another device.
Now we are measuring an outcome: the share brought someone to the site.
If the link carries enough attribution information, the visit can be connected to a share channel or source. But it is still a new event, not a continuation of the first record.
One Event Is the Cause, the Other Is the Outcome
Share action | | may cause vShared-link visit But: 1 sharecan produce0, 1, or many visitsThis is where one counter can easily break the analytics model.
If shares increases both when Share is clicked and when a shared link is opened, one metric starts meaning two different things.
After that, it becomes impossible to answer how many actual share actions happened and how many visits they produced.
One Share Can Produce Zero Visits
Copy Link confirms only that the user obtained the link in the clipboard.
They may close the tab, change their mind, or use the URL later.
That is why the Share metric is useful on its own: it measures intent to distribute the content even if no outcome has happened yet.
One Share Can Produce Many Visits
1 Share action shared into group chat | +-- Visit A +-- Visit B +-- Visit C +-- Visit DThis is another reason not to collapse the events into one number.
One share into a group chat or public channel may produce many visits.
If the system expects one Share action to equal one visit, it models reality incorrectly.
These Events Belong to Different People
The Share action belongs to the person who shares.
The shared-link visit belongs to the person who opens the link.
Even if both users are authenticated, they are different actors. If they are guests, the system may not know any stable identity at all.
That is why I do not try to model this as one "share row" that is later updated by another person.
I Separate These Events in Code Too
final readonly class ShareRecorded{ public function __construct( public int $contentId, public string $channel, ) { }} final readonly class SharedLinkVisited{ public function __construct( public int $contentId, public ?string $source, ) { }Event naming matters here.
ShareRecorded does not promise a visit. SharedLinkVisited does not claim that we observed the original Share action.
When the concepts are separated in code, it becomes harder to accidentally mix them in aggregation or dashboards.
They Should Be Separate Metrics in the Dashboard Too
SHARES128 ATTRIBUTED VISITS46 VISITS PER SHARE0.36SHARES shows how many share actions users performed.
ATTRIBUTED VISITS shows how many visits could be connected to shared links.
VISITS PER SHARE is a derived metric that helps estimate how effectively Share actions produce visits.
A Shared-Link Visit Needs Attribution, a Share Action Does Not
A Share action happens directly inside our interface, so the event source is known immediately.
A visit is harder. The request arrives later, and the system needs a way to understand that the URL came from a share flow.
This can be an explicit source marker, a share identifier, or another attribution mechanism. The implementation may vary, but the event model remains the same.
Not Every Visit Can Be Honestly Attributed to a Specific Share
A link may be forwarded again, have parameters removed, be pasted into another service, or be opened through an environment that changes the URL.
That is why I do not turn every direct visit into "probably a share."
If there is no attribution evidence, it is better to keep the visit unattributed than artificially inflate share effectiveness.
Deduplication Rules Can Be Different Too
For a Share action, we may decide whether repeated clicks by the same user in a short period should count separately.
Visits have different rules: one person may open the shared link several times, while several people may open the same URL.
One universal deduplication rule for both events will almost certainly distort at least one metric.
Together These Events Form a Funnel, Not One Counter
Article view | vShare action | vShared-link visit | vFurther engagementOnce the events are separated, much more useful questions become possible.
Which articles are shared most often? Which share channel produces more visits? Which visitors continue reading other pages? Which content gets many Share actions but almost no visits?
One combined counter cannot answer any of these questions.
What Breaks When Cause and Outcome Are Mixed
- SHARES stops meaning the number of actual share actions.
- Share-to-visit conversion can no longer be calculated.
- One popular shared link can artificially create dozens of "shares."
- Deduplication rules become contradictory.
- Intent can no longer be separated from outcome.
- Analytics starts looking more active than the real user behavior.
My Simple Model for These Events
Share action content_idchannelactor contextoccurred_at Shared-link visit content_idshare sourcevisitor contextoccurred_atI do not require both events to live in one table or even share the same schema shape.
What matters more is that every record has one unambiguous meaning.
If an event answers one question, it is easier to test, aggregate, and display in analytics.
Tests Become Clearer When the Events Are Separate
public function test_copy_link_records_share_action(): void{ // user performs Copy Link $this->assertSame( 1, $this->sharesFor($post), );} public function test_shared_link_visit_does_not_increment_shares(): void{ // another visitor opens attributed link $this->assertSame( 1,One Metric Should Have One Meaning
The most useful lesson for me here is not only about share analytics.
When one action may cause another outcome later, I try not to collapse them into one event simply because they are causally connected.
A Share action is the cause. A shared-link visit is a possible outcome. They are related, but they should be measured separately.
If one counter means both "someone shared" and "someone arrived through the link," it is no longer one metric. It is two stories mixed together.



