Google Analytics works on a flowchart when assigning the marketing source to the session. First looking for defined parameters such as gclid or UTM parameters to set the marketing source, and then falling back on the document referrer, and eventually if unknown it sets the channel as Direct.
This flowchart occurs every time that a hit (pageview, event, eccomerce) is sent to Google Analytics.
The first time you visit a single page application all of the HTML is loaded and the referrer is set. Then for each navigation through the site, the URL may change but the whole HTML does not reload and therefore the referrer does not change.
Step1: A user clicks on a CPC advertisement and lands on the SPA where the URL and Referrer are set as:
Every time a user’s campaign source changes, Analytics opens a new session.”
Google Analytics then continues down the marketing attribution flowchart, until it gets to the document referrer, where it sees it as www.google.com. This domain is on its Search Engine list so it sets the marketing source as Organic Google and sets a new session in Google Analytics with the CPC session coming to an end.
A solution to this is to ensure all internal links (page changes) do not include the referrer in the Google Analytics send beacon.
With a standard website where the full HTML is loaded with each page change, the referrer is only set when the current hostname differs from the referrer hostname. As all internal links (page changes) on a SPA should contain the same hostname as the referrer it is not necessary to pass this variable. This is achieved by setting the variable as undefined.