Skip to content

[DO NOT MERGE] Add Google Analytics 4 #1341

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 17 commits into
base: main
Choose a base branch
from
Open

[DO NOT MERGE] Add Google Analytics 4 #1341

wants to merge 17 commits into from

Conversation

quietbits
Copy link
Contributor

@quietbits quietbits commented Apr 18, 2025

Added Google Tag Manager and Google Analytics 4.

@github-project-automation github-project-automation bot moved this to Backlog (Not Ready) in DevX Apr 18, 2025
@quietbits quietbits marked this pull request as draft April 18, 2025 20:42
@stellar-jenkins
Copy link

Something went wrong with PR preview build please check

@stellar-jenkins
Copy link

@stellar-jenkins
Copy link

Copy link

socket-security bot commented Apr 23, 2025

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Added@​next/​third-parties@​15.3.11001008099100
Addedthird-party-capital@​1.0.201001009785100

View full report

@stellar-jenkins
Copy link

@stellar-jenkins
Copy link

@stellar-jenkins
Copy link

@stellar-jenkins
Copy link

@quietbits quietbits linked an issue Apr 24, 2025 that may be closed by this pull request
@quietbits quietbits marked this pull request as ready for review April 24, 2025 13:59
Copy link
Member

@leighmcculloch leighmcculloch Apr 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can whether the GA code is enabled be configurable, so that when building to static and deploying inside quickstart it can be disabled? Or will the production check cover that?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a good question, @leighmcculloch . @fnando, Should we add a flag to disable tracking in Quickstart? 🙏

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it makes sense making this configurable for the quickstart.

@kanwalpreetd
Copy link
Contributor

kanwalpreetd commented Apr 24, 2025

@quietbits Signed transaction XDR (containing full transaction details and signature) is being leaked in requests to Google such as below (in query parameters dl and dr in below request):

POST /g/collect?v=2&tid=G-83WWFR45KS&gtm=45je54n0v9132785736za200zb9119700007&_p=1745531908247&gcd=13l3l3l3l1l1&npa=0&dma=0&tag_exp=102887800~103051953~103077950~103106314~103106316~103116025~103130357~103130359~103200001&ptag_exp=101509157~102887800~103051953~103077950~103106314~103106316~103116026~103130495~103130497~103200004&cid=566760639.1745531891&ul=en-us&sr=1512x982&frm=0&pscdl=noapi&_eu=AEAAAAI&_s=39&dl=https%3A%2F%2Flaboratory-pr1341.previews.kube001.services.stellar-ops.com%2Fsmart-contracts%2Fcontract-explorer%3F%24%3Dnetwork%24id%3Dtestnet%26label%3DTestnet%26horizonUrl%3Dhttps%3A%2F%2F%2F%2Fhorizon-testnet.stellar.org%26rpcUrl%3Dhttps%3A%2F%2F%2F%2Fsoroban-testnet.stellar.org%26passphrase%3DTest%2520SDF%2520Network%2520%2F%3B%2520September%25202015%3B%26transaction%24build%24classic%24operations%40%24operation_type%3Dpayment%26params%24destination%3DGAXM7NOWKEQF7U36I3E7UGDJKFB7PVC5XUH233WDQXXZZ4G26I4CIYA6%26asset%24code%3D%26issuer%3D%26type%3Dnative%3B%26amount%3D5%3B%26source_account%3D%3B%3B%3B%26soroban%24operation%24params%40%3B%3B%3B%26params%24source_account%3DMAXM7NOWKEQF7U36I3E7UGDJKFB7PVC5XUH233WDQXXZZ4G26I4CIAAAAAAAAAAAAFM4E%26seq_num%3D2683121904386050%26memo%3Dnone%3B%26isValid%24params%3Atrue%26operations%3Atrue%3B%3B%26sign%24activeView%3Doverview%26importXdr%3DAAAAAgAAAQAAAAAAAAAAAS7PtdZRIF%2F%2FTfkbJ%2BhhpUUP31F29D63uw4XvnPDa8jgkAAAAZAAJiEkAAAACAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAABAAAAAC7PtdZRIF%2F%2FTfkbJ%2BhhpUUP31F29D63uw4XvnPDa8jgkAAAAAAAAAAAC%2BvCAAAAAAAAAAAA%3D%3B%26simulate%24triggerOnLaunch%3Afalse%3B%3B%26xdr%24blob%3DAAAAAgAAAQAAAAAAAAAAAS7PtdZRIF%2F%2FTfkbJ%2BhhpUUP31F29D63uw4XvnPDa8jgkAAAAZAAJiEkAAAACAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAABAAAAAC7PtdZRIF%2F%2FTfkbJ%2BhhpUUP31F29D63uw4XvnPDa8jgkAAAAAAAAAAAC%2BvCAAAAAAAAAAAEnmEJ3AAAAQK0zw%2Bb7D5sUpFPY3H%2BkrlWFKmqX%2F%2FxXQ8%2BLW1J8RxaKDRIzoBycaBbODRYF6FwTZST%2BSduGgQykcTxzGM%2BtLxAg%3D%26jsonString%3D%257Btest%257D%3B%26smartContracts%24explorer%24contractId%3DCAXVC7RJGN6I2WEOXPAYSX24TJ4W2BB3MJEGNFENGTSPR2XV4ZGS7ZGV%3B%3B&dr=https%3A%2F%2Flaboratory-pr1341.previews.kube001.services.stellar-ops.com%2Ftransaction%2Fsubmit%3F%24%3Dnetwork%24id%3Dtestnet%26label%3DTestnet%26horizonUrl%3Dhttps%3A%2F%2F%2F%2Fhorizon-testnet.stellar.org%26rpcUrl%3Dhttps%3A%2F%2F%2F%2Fsoroban-testnet.stellar.org%26passphrase%3DTest%2520SDF%2520Network%2520%2F%3B%2520September%25202015%3B%26transaction%24build%24classic%24operations%40%24operation_type%3Dpayment%26params%24destination%3DGAXM7NOWKEQF7U36I3E7UGDJKFB7PVC5XUH233WDQXXZZ4G26I4CIYA6%26asset%24code%3D%26issuer%3D%26type%3Dnative%3B%26amount%3D5%3B%26source_account%3D%3B%3B%3B%26soroban%24operation%24params%40%3B%3B%3B%26params%24source_account%3DMAXM7NOWKEQF7U36I3E7UGDJKFB7PVC5XUH233WDQXXZZ4G26I4CIAAAAAAAAAAAAFM4E%26seq_num%3D2683121904386050%26memo%3Dnone%3B%26isValid%24params%3Atrue%26operations%3Atrue%3B%3B%26sign%24activeView%3Doverview%26importXdr%3DAAAAAgAAAQAAAAAAAAAAAS7PtdZRIF%2F%2FTfkbJ%2BhhpUUP31F29D63uw4XvnPDa8jgkAAAAZAAJiEkAAAACAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAABAAAAAC7PtdZRIF%2F%2FTfkbJ%2BhhpUUP31F29D63uw4XvnPDa8jgkAAAAAAAAAAAC%2BvCAAAAAAAAAAAA%3D%3B%26simulate%24triggerOnLaunch%3Afalse%3B%3B%26xdr%24blob%3DAAAAAgAAAQAAAAAAAAAAAS7PtdZRIF%2F%2FTfkbJ%2BhhpUUP31F29D63uw4XvnPDa8jgkAAAAZAAJiEkAAAACAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAABAAAAAC7PtdZRIF%2F%2FTfkbJ%2BhhpUUP31F29D63uw4XvnPDa8jgkAAAAAAAAAAAC%2BvCAAAAAAAAAAAEnmEJ3AAAAQK0zw%2Bb7D5sUpFPY3H%2BkrlWFKmqX%2F%2FxXQ8%2BLW1J8RxaKDRIzoBycaBbODRYF6FwTZST%2BSduGgQykcTxzGM%2BtLxAg%3D%26jsonString%3D%257Btest%257D%3B%26smartContracts%24explorer%24contractId%3DCAXVC7RJGN6I2WEOXPAYSX24TJ4W2BB3MJEGNFENGTSPR2XV4ZGS7ZGV%3B%3B&sid=1745531891&sct=1&seg=1&dt=Stellar%20Lab&tfd=1006074 HTTP/2
Host: www.google-analytics.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:137.0) Gecko/20100101 Firefox/137.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Content-Type: text/plain;charset=UTF-8
Referer: https://laboratory-pr1341.previews.kube001.services.stellar-ops.com/
Content-Length: 22
Origin: https://laboratory-pr1341.previews.kube001.services.stellar-ops.com
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: no-cors
Sec-Fetch-Site: cross-site
Priority: u=6
Pragma: no-cache
Cache-Control: no-cache
Te: trailers

en=page_view&_et=30047

Because, as we browse through the lab application and use different features such as signing, simulate, view in XDR viewer etc., most of the data is passed through and added to URL query parameters, which is recorded by the Google Analytics plugin. For e.g. - the above request contains the following (in dl query parameter):

https://laboratory-pr1341.previews.kube001.services.stellar-ops.com/smart-contracts/contract-explorer?$=network$id=testnet&label=Testnet&horizonUrl=https:////horizon-testnet.stellar.org&rpcUrl=https:////soroban-testnet.stellar.org&passphrase=Test%20SDF%20Network%20/;%20September%202015;&transaction$build$classic$operations@$operation_type=payment&params$destination=GAXM7NOWKEQF7U36I3E7UGDJKFB7PVC5XUH233WDQXXZZ4G26I4CIYA6&asset$code=&issuer=&type=native;&amount=5;&source_account=;;;&soroban$operation$params@;;;&params$source_account=MAXM7NOWKEQF7U36I3E7UGDJKFB7PVC5XUH233WDQXXZZ4G26I4CIAAAAAAAAAAAAFM4E&seq_num=2683121904386050&memo=none;&isValid$params:true&operations:true;;&sign$activeView=overview&importXdr=AAAAAgAAAQAAAAAAAAAAAS7PtdZRIF//TfkbJ+hhpUUP31F29D63uw4XvnPDa8jgkAAAAZAAJiEkAAAACAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAABAAAAAC7PtdZRIF//TfkbJ+hhpUUP31F29D63uw4XvnPDa8jgkAAAAAAAAAAAC+vCAAAAAAAAAAAA=;&simulate$triggerOnLaunch:false;;&xdr$blob=AAAAAgAAAQAAAAAAAAAAAS7PtdZRIF//TfkbJ+hhpUUP31F29D63uw4XvnPDa8jgkAAAAZAAJiEkAAAACAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAABAAAAAC7PtdZRIF//TfkbJ+hhpUUP31F29D63uw4XvnPDa8jgkAAAAAAAAAAAC+vCAAAAAAAAAAAEnmEJ3AAAAQK0zw+b7D5sUpFPY3H+krlWFKmqX//xXQ8+LW1J8RxaKDRIzoBycaBbODRYF6FwTZST+SduGgQykcTxzGM+tLxAg=&jsonString=%7Btest%7D;&smartContracts$explorer$contractId=CAXVC7RJGN6I2WEOXPAYSX24TJ4W2BB3MJEGNFENGTSPR2XV4ZGS7ZGV;;

which contains signed XDR: xdr$blob=AAAAAgAAAQAAAAAAAAAAAS7PtdZRIF//TfkbJ+hhpUUP31F29D63uw4XvnPDa8jgkAAAAZAAJiEkAAAACAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAABAAAAAC7PtdZRIF//TfkbJ+hhpUUP31F29D63uw4XvnPDa8jgkAAAAAAAAAAAC+vCAAAAAAAAAAAEnmEJ3AAAAQK0zw+b7D5sUpFPY3H+krlWFKmqX//xXQ8+LW1J8RxaKDRIzoBycaBbODRYF6FwTZST+SduGgQykcTxzGM+tLxAg=

I suppose this is not ideal, because leaking signed XDR to third parties can lead to abuse of functionality such as simulate, and front running transactions (as in other issue earlier).

@leighmcculloch
Copy link
Member

Even unsigned xdr would be best not to capture. Unsigned txs can contain signed auth entries within, or communicate an intent to take some action that might be non public information.

@kanwalpreetd
Copy link
Contributor

@leighmcculloch Unsigned txs can contain signed auth entries within -> is this wrt Soroban transactions, or is it somehow possible with plain Stellar transactions as well?

Seems like you can't rely on excluding just certain URL paths for the integration, as the application currently appends parameters from the UI to URL progressively. So doesn't matter which URL path you are on, it can still contain XDR info. Unless there is a way to strip certain URL params from being included in tracking, the application will have to be changed to support this integration.

@quietbits
Copy link
Contributor Author

Thanks for the feedback, @kanwalpreetd and @leighmcculloch! 🙌 We can't control what is submitted to Google Analytics 4 from the client. I think it grabs the whole URL, and then you decide what to keep on the dashboard side. We might need to ask our SEO masters to confirm this (@alexisdowney1 @Fastish 🙏 ).

What if we moved away from storing everything in the URL? We mainly want this to allow sharing, but we could provide a button to create a shareable URL (we already do that for requests in API Explorer, for example). With this approach, we save the app's state in the browser's session storage (or local storage if we need to clear the store data manually). That way, we:

  • Don't need to worry about leaking sensitive information to third parties from the URL;
  • Don't need to worry about running out of space in the URL (which already happens with long XDRs);
  • We can better control what the shared URL is (instead of always sharing the whole thing);
  • We could have better warnings for users when loading data from a URL because persisting data would come from the session storage, and only a shared URL would need to be parsed to load the data.
  • Lab URL would look nicer (currently, it's very long and not very readable);

What are your thoughts? @janewang @sagpatil @jeesunikim 🙏

@quietbits quietbits marked this pull request as draft April 25, 2025 13:15
@quietbits quietbits changed the title Add Google Analytics 4 [DO NOT MERGE] Add Google Analytics 4 Apr 25, 2025
@janewang
Copy link
Contributor

I know sharing URLs across different users is a key feature based on user interviews.

If you create a URL and share it to me without URL params, I don't have the data stored in session local storage. How would I be able to load the URL?

@janewang
Copy link
Contributor

janewang commented Apr 25, 2025

Also the CLI links back to Lab for signing passing data using the URL. That's an existing feature.

In recent conversations, it appears that Lab needs a backend.

Once a product grows to a point where it runs into the same root issue of not having a backend, a rational decision is to add the backend so the product can move forward. @sagpatil We have encountered this issue of not having a backend multiple times, a higher frequency as of late. What are your thoughts?

@alexisdowney1
Copy link

alexisdowney1 commented Apr 25, 2025

The current limitations can't be fixed solely through GTM / GA4 but the only other additional thing I can do is
Add URL Parameter Redaction. I can create a solution that removes sensitive query parameters from any URL before it's sent to GA4. But I would have to know the structure of the sensitive data in the query, a few from exploring are:

`// List of sensitive parameters to redact
  // Add any parameter names that might contain sensitive data
  var sensitiveParams = [
    "xdr",           // XDR info 
    "auth",          // Authentication tokens
    "token",         // Tokens
    "key",           // API keys
    "signature",     // Signatures
    "hash",          // Hashes
    "id",            // IDs that might be sensitive
    "account",       // Account identifiers
    "user",          // User information
    "email",         // Email addresses
    "name",          // Names
    "pass",          // Passwords
    "transaction",   // Transaction data
    "wallet",        // Wallet information
    "address",       // Addresses
 
    "passphrase",    // Network passphrase
    "horizonUrl",    // API endpoint
    "rpcUrl",        // RPC endpoint
    "operation_type", // Transaction operation type
    "params",        // Operation parameters
    "secret",        // Secret keys
    "seed",          // Seed phrases
    "memo",          // Transaction memos
    "source",        // Source accounts
    "destination",   // Destination accounts
    "asset",         // Asset information
    "amount",        // Transaction amounts
    "signer",        // Signer information
    "fee",           // Fee information`

@quietbits
Copy link
Contributor Author

I know sharing URLs across different users is a key feature based on user interviews.

If you create a URL and share it to me without URL params, I don't have the data stored in session local storage. How would I be able to load the URL?

@janewang , link sharing will still be available. We would just create the link on demand (users would need to click a button to get a link). When Lab loads, we would detect params in the URL and parse them, so they will be added to the session storage and removed from the URL.

Generated shared URL example for "View XDR":

https://lab.stellar.org/xdr/view?$=network$id=mainnet&label=Mainnet&horizonUrl=https:////horizon.stellar.org&rpcUrl=https:////mainnet.sorobanrpc.com&passphrase=Public%20Global%20Stellar%20Network%20/;%20September%202015;&xdr$blob=AAAABQAAAABNaBZJk5idBm4//YrzSeX17zmI6GXojYX+w86x50onj6QAAAAAAA1AWAAAAAgAAAABkaLLKNmZdHWkDBsrXUG4+Uph+QftZp7UTNdvS4uL1LAADT04DYEKfAAASLgAAAAEAAAAAAAAAAAAAAABoC8G2AAAAAAAAAAEAAAAAAAAAGAAAAAAAAAAB1//5EvQrxHWArEJHy9KH03yEtRE0DIeoyrbPMHLurCgQAAAAFcGxhbnQAAAAAAAACAAAAEgAAAAAAAAAAZGiyyjZmXR1pAwbK11BuPlKYfkH7Wae1EzXb0uLi9SwAAAAKAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAHX//kS9CvEdYCsQkfL0ofTfIS1ETQMh6jKts8wcu6sKBAAAAAVwbGFudAAAAAAAAAIAAAASAAAAAAAAAABkaLLKNmZdHWkDBsrXUG4+Uph+QftZp7UTNdvS4uL1LAAAAAoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAQAAAAfbLBQpDUlk44BfJSfdEyk5ul+z//MrFazC//q4//QkQEWJwAAAAMAAAAGAAAAAdf+RL0K8R1gKxCR8vSh9N8hLURNAyHqMq2zzBy7qwoEAAAAEAAAAAEAAAACAAAADwAAAAVCbG9jawAAAAAAAAMAAK24AAAAAAAAAAYAAAAB1//5EvQrxHWArEJHy9KH03yEtRE0DIeoyrbPMHLurCgQAAAAQAAAAAQAAAAMAAAAPAAAABFBhaWwAAAASAAAAAAAAAABkaLLKNmZdHWkDBsrXUG4+Uph+QftZp7UTNdvS4uL1LAAAAAMAAK24AAAAAAAAAAYAAAAB1//5EvQrxHWArEJHy9KH03yEtRE0DIeoyrbPMHLurCgQAAAAUAAAAAQBCXhIAAFFYAAAFwAAAAAAAA09OAAAAAeLi9SwAAABAXm1EIW7IM3exzWOOaGQRCM3y5NgedrOrCeLdkqcbW9QSd+PLUvXrUEu5E9AP+e//2//4PBelQOsjWw9K1T4w96BQAAAAAAAAAB0onj6QAAAEBVcubqpkFOWmoERt1ezch3hWWDK1Fi+GQAa7YnkR3mjfItdHX+62Ezp4z5yeZayDccdMDEW5sKo3wWa7Wu5AgE;;

Lab URL after initial load (params stored in session storage):

https://lab.stellar.org/xdr/view

We can think of ways to improve the UX if the generic approach is acceptable. I think it's just a matter of time before we run out of space to store state in the URL (most browsers allow max 2000 characters or so).

@quietbits
Copy link
Contributor Author

The current limitations can't be fixed solely through GTM / GA4 but the only other additional thing I can do is Add URL Parameter Redaction. I can create a solution that removes sensitive query parameters from any URL before it's sent to GA4. But I would have to know the structure of the sensitive data in the query, a few from exploring are:

`// List of sensitive parameters to redact
  // Add any parameter names that might contain sensitive data
  var sensitiveParams = [
    "xdr",           // XDR info 
    "auth",          // Authentication tokens
    "token",         // Tokens
    "key",           // API keys
    "signature",     // Signatures
    "hash",          // Hashes
    "id",            // IDs that might be sensitive
    "account",       // Account identifiers
    "user",          // User information
    "email",         // Email addresses
    "name",          // Names
    "pass",          // Passwords
    "transaction",   // Transaction data
    "wallet",        // Wallet information
    "address",       // Addresses
 
    "passphrase",    // Network passphrase
    "horizonUrl",    // API endpoint
    "rpcUrl",        // RPC endpoint
    "operation_type", // Transaction operation type
    "params",        // Operation parameters
    "secret",        // Secret keys
    "seed",          // Seed phrases
    "memo",          // Transaction memos
    "source",        // Source accounts
    "destination",   // Destination accounts
    "asset",         // Asset information
    "amount",        // Transaction amounts
    "signer",        // Signer information
    "fee",           // Fee information`

Thanks, @alexisdowney1 ! Could we exclude all search params? Or keep only the ones we definitely need for tracking (for example, network). Like, we would exclude all params by default, but add only the ones we want to track.

@kanwalpreetd
Copy link
Contributor

Thanks, @alexisdowney1 ! Could we exclude all search params? Or keep only the ones we definitely need for tracking (for example, network). Like, we would exclude all params by default, but add only the ones we want to track.

@quietbits +1. The approach you mentioned above (whitelisting params that can be excluded in tracking) is better for security. If we follow the blacklisting approach (excluding a list of params for tracking), that has the potential to expose sensitive params to be tracked in cases where we miss certain params, when a parameter name is changed, or a new sensitive param is added.

@stellar-jenkins
Copy link

@stellar-jenkins
Copy link

@stellar-jenkins
Copy link

@quietbits quietbits marked this pull request as ready for review May 6, 2025 18:32
@kanwalpreetd
Copy link
Contributor

Still see the following request with leaked XDR (the XDR data is being leaked in both URL query parameters as well POST body to Google):

POST /g/collect?v=2&tid=G-83WWFR45KS&gtm=45je5560h1v9132785736za200zb9119700007&_p=1746636576960&gcd=13l3l3l3l1l1&npa=0&dma=0&tag_exp=101509156~102015665~103101750~103101752~103116025~103200001~103231718~103231720~103233424~103251618~103251620~103252644~103252646~103284320~103284322~103301114~103301116&ptag_exp=101509157~103101750~103101752~103116026~103200004~103231718~103231720~103233427~103251618~103251620~103252644~103252646~103284320~103284322~103301114~103301116&cid=828257119.1746636577&ul=en-us&sr=1512x982&frm=0&pscdl=noapi&_eu=AEAAAAQ&dl=https%3A%2F%2Flaboratory-pr1341.previews.kube001.services.stellar-ops.com%2Fsmart-contracts%2Fcontract-list%3F%24%3Dnetwork%24id%3Dtestnet%26label%3DTestnet%26horizonUrl%3Dhttps%3A%2F%2F%2F%2Fhorizon-testnet.stellar.org%26rpcUrl%3Dhttps%3A%2F%2F%2F%2Fsoroban-testnet.stellar.org%26passphrase%3DTest%2520SDF%2520Network%2520%2F%3B%2520September%25202015%3B%26transaction%24build%24classic%24operations%40%24operation_type%3Dpayment%26params%24destination%3DMAFGI4PPDOPTUBVQUFFC6DEX7EP5V6CXHONBNABOZBCV2QTG4GWFCAAAAAAAAAAAAHVGS%26asset%24code%3D%26issuer%3D%26type%3Dnative%3B%26amount%3D5%3B%26source_account%3D%3B%3B%3B%26soroban%24operation%24params%40%3B%3B%3B%26params%24source_account%3DGAFGI4PPDOPTUBVQUFFC6DEX7EP5V6CXHONBNABOZBCV2QTG4GWFCDVE%26seq_num%3D3631072726220801%26memo%3Dnone%3B%26isValid%24params%3Atrue%26operations%3Atrue%3B%3B%26sign%24activeView%3Doverview%26importXdr%3DAAAAAgAAAAAKZHHvG586BrChSi8Ml%2F%2Fkf2vhXO5oWgC7IRV1CZuGsUQAAAGQADOZxAAAAAQAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAQAAAQAAAAAAAAAAAQpkce8bnzoGsKFKLwyX%2BR%2F%2Fa%2BFc7mhaALshFXUJm4axRAAAAAAAAAAAC%2BvCAAAAAAAAAAAA%3D%3B%26simulate%24triggerOnLaunch%3Afalse%3B%3B%26xdr%24blob%3DAAAAAgAAAAAKZHHvG586BrChSi8Ml%2F%2Fkf2vhXO5oWgC7IRV1CZuGsUQAAAGQADOZxAAAAAQAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAQAAAQAAAAAAAAAAAQpkce8bnzoGsKFKLwyX%2BR%2F%2Fa%2BFc7mhaALshFXUJm4axRAAAAAAAAAAAC%2BvCAAAAAAAAAAAFm4axRAAAAQCmlJhCSS%2BQUAg4pmJye1AgVTeZCPcYmLkeF4%2F%2FTuKJ6QXtPjQNSf%2F%2FoeQsVOznBaoTZXUiRUr8YVZQKb4OMVnWws%3D%26jsonString%3D%257B%250A%2520%2520%2522tx%2522%3A%2520%257B%250A%2520%2520%2520%2520%2522tx%2522%3A%2520%257B%250A%2520%2520%2520%2520%2520%2520%2522source_account%2522%3A%2520%2522GAFGI4PPDOPTUBVQUFFC6DEX7EP5V6CXHONBNABOZBCV2QTG4GWFCDVE%2522%2C%250A%2520%2520%2520%2520%2520%2520%2522fee%2522%3A%2520100%2C%250A%2520%2520%2520%2520%2520%2520%2522seq_num%2522%3A%25203631072726220801%2C%250A%2520%2520%2520%2520%2520%2520%2522cond%2522%3A%2520%257B%250A%2520%2520%2520%2520%2520%2520%2520%2520%2522time%2522%3A%2520%257B%250A%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2522min_time%2522%3A%25200%2C%250A%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2522max_time%2522%3A%25200%250A%2520%2520%2520%2520%2520%2520%2520%2520%257D%250A%2520%2520%2520%2520%2520%2520%257D%2C%250A%2520%2520%2520%2520%2520%2520%2522memo%2522%3A%2520%2522none%2522%2C%250A%2520%2520%2520%2520%2520%2520%2522operations%2522%3A%2520%255B%250A%2520%2520%2520%2520%2520%2520%2520%2520%257B%250A%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2522source_account%2522%3A%2520null%2C%250A%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2522body%2522%3A%2520%257B%250A%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2522payment%2522%3A%2520%257B%250A%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2522destination%2522%3A%2520%2522MAFGI4PPDOPTUBVQUFFC6DEX7EP5V6CXHONBNABOZBCV2QTG4GWFCAAAAAAAAAAAAHVGS%2522%2C%250A%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2522asset%2522%3A%2520%2522native%2522%2C%250A%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2522amount%2522%3A%252050000000%250A%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%257D%250A%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%257D%250A%2520%2520%2520%2520%2520%2520%2520%2520%257D%250A%2520%2520%2520%2520%2520%2520%255D%2C%250A%2520%2520%2520%2520%2520%2520%2522ext%2522%3A%2520%2522v0%2522%250A%2520%2520%2520%2520%257D%2C%250A%2520%2520%2520%2520%2522signatures%2522%3A%2520%255B%250A%2520%2520%2520%2520%2520%2520%257B%250A%2520%2520%2520%2520%2520%2520%2520%2520%2522hint%2522%3A%2520%252266e1ac51%2522%2C%250A%2520%2520%2520%2520%2520%2520%2520%2520%2522signature%2522%3A%2520%252229a52610924be414020e29989c9ed408154de6423dc6262e4785e3f4ee289e905ed3e340d49ffe8790b153b39c16a84d95d489152bf1855940a6f838c5675b0b%2522%250A%2520%2520%2520%2520%2520%2520%257D%250A%2520%2520%2520%2520%255D%250A%2520%2520%257D%250A%257D%3B%3B&dr=https%3A%2F%2Flaboratory-pr1341.previews.kube001.services.stellar-ops.com%2Fsmart-contracts%2Fcontract-explorer%3F%24%3Dnetwork%24id%3Dtestnet%26label%3DTestnet%26horizonUrl%3Dhttps%3A%2F%2F%2F%2Fhorizon-testnet.stellar.org%26rpcUrl%3Dhttps%3A%2F%2F%2F%2Fsoroban-testnet.stellar.org%26passphrase%3DTest%2520SDF%2520Network%2520%2F%3B%2520September%25202015%3B%26transaction%24build%24classic%24operations%40%24operation_type%3Dpayment%26params%24destination%3DMAFGI4PPDOPTUBVQUFFC6DEX7EP5V6CXHONBNABOZBCV2QTG4GWFCAAAAAAAAAAAAHVGS%26asset%24code%3D%26issuer%3D%26type%3Dnative%3B%26amount%3D5%3B%26source_account%3D%3B%3B%3B%26soroban%24operation%24params%40%3B%3B%3B%26params%24source_account%3DGAFGI4PPDOPTUBVQUFFC6DEX7EP5V6CXHONBNABOZBCV2QTG4GWFCDVE%26seq_num%3D3631072726220801%26memo%3Dnone%3B%26isValid%24params%3Atrue%26operations%3Atrue%3B%3B%26sign%24activeView%3Doverview%26importXdr%3DAAAAAgAAAAAKZHHvG586BrChSi8Ml%2F%2Fkf2vhXO5oWgC7IRV1CZuGsUQAAAGQADOZxAAAAAQAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAQAAAQAAAAAAAAAAAQpkce8bnzoGsKFKLwyX%2BR%2F%2Fa%2BFc7mhaALshFXUJm4axRAAAAAAAAAAAC%2BvCAAAAAAAAAAAA%3D%3B%26simulate%24triggerOnLaunch%3Afalse%3B%3B%26xdr%24blob%3DAAAAAgAAAAAKZHHvG586BrChSi8Ml%2F%2Fkf2vhXO5oWgC7IRV1CZuGsUQAAAGQADOZxAAAAAQAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAQAAAQAAAAAAAAAAAQpkce8bnzoGsKFKLwyX%2BR%2F%2Fa%2BFc7mhaALshFXUJm4axRAAAAAAAAAAAC%2BvCAAAAAAAAAAAFm4axRAAAAQCmlJhCSS%2BQUAg4pmJye1AgVTeZCPcYmLkeF4%2F%2FTuKJ6QXtPjQNSf%2F%2FoeQsVOznBaoTZXUiRUr8YVZQKb4OMVnWws%3D%26jsonString%3D%257B%250A%2520%2520%2522tx%2522%3A%2520%257B%250A%2520%2520%2520%2520%2522tx%2522%3A%2520%257B%250A%2520%2520%2520%2520%2520%2520%2522source_account%2522%3A%2520%2522GAFGI4PPDOPTUBVQUFFC6DEX7EP5V6CXHONBNABOZBCV2QTG4GWFCDVE%2522%2C%250A%2520%2520%2520%2520%2520%2520%2522fee%2522%3A%2520100%2C%250A%2520%2520%2520%2520%2520%2520%2522seq_num%2522%3A%25203631072726220801%2C%250A%2520%2520%2520%2520%2520%2520%2522cond%2522%3A%2520%257B%250A%2520%2520%2520%2520%2520%2520%2520%2520%2522time%2522%3A%2520%257B%250A%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2522min_time%2522%3A%25200%2C%250A%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2522max_time%2522%3A%25200%250A%2520%2520%2520%2520%2520%2520%2520%2520%257D%250A%2520%2520%2520%2520%2520%2520%257D%2C%250A%2520%2520%2520%2520%2520%2520%2522memo%2522%3A%2520%2522none%2522%2C%250A%2520%2520%2520%2520%2520%2520%2522operations%2522%3A%2520%255B%250A%2520%2520%2520%2520%2520%2520%2520%2520%257B%250A%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2522source_account%2522%3A%2520null%2C%250A%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2522body%2522%3A%2520%257B%250A%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2522payment%2522%3A%2520%257B%250A%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2522destination%2522%3A%2520%2522MAFGI4PPDOPTUBVQUFFC6DEX7EP5V6CXHONBNABOZBCV2QTG4GWFCAAAAAAAAAAAAHVGS%2522%2C%250A%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2522asset%2522%3A%2520%2522native%2522%2C%250A%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2522amount%2522%3A%252050000000%250A%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%257D%250A%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%257D%250A%2520%2520%2520%2520%2520%2520%2520%2520%257D%250A%2520%2520%2520%2520%2520%2520%255D%2C%250A%2520%2520%2520%2520%2520%2520%2522ext%2522%3A%2520%2522v0%2522%250A%2520%2520%2520%2520%257D%2C%250A%2520%2520%2520%2520%2522signatures%2522%3A%2520%255B%250A%2520%2520%2520%2520%2520%2520%257B%250A%2520%2520%2520%2520%2520%2520%2520%2520%2522hint%2522%3A%2520%252266e1ac51%2522%2C%250A%2520%2520%2520%2520%2520%2520%2520%2520%2522signature%2522%3A%2520%252229a52610924be414020e29989c9ed408154de6423dc6262e4785e3f4ee289e905ed3e340d49ffe8790b153b39c16a84d95d489152bf1855940a6f838c5675b0b%2522%250A%2520%2520%2520%2520%2520%2520%257D%250A%2520%2520%2520%2520%255D%250A%2520%2520%257D%250A%257D%3B%3B&sid=1746636577&sct=1&seg=1&dt=Stellar%20Lab&_s=23&tfd=391254 HTTP/2
Host: www.google-analytics.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:138.0) Gecko/20100101 Firefox/138.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Content-Type: text/plain;charset=UTF-8
Referer: https://laboratory-pr1341.previews.kube001.services.stellar-ops.com/
Content-Length: 8131
Origin: https://laboratory-pr1341.previews.kube001.services.stellar-ops.com
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: no-cors
Sec-Fetch-Site: cross-site
Priority: u=6
Pragma: no-cache
Cache-Control: no-cache
Te: trailers

en=page_view&_et=3311
en=page_view&_et=2456&dl=https%3A%2F%2Flaboratory-pr1341.previews.kube001.services.stellar-ops.com%2Fsmart-contracts%2Fcontract-explorer%3F%24%3Dnetwork%24id%3Dtestnet%26label%3DTestnet%26horizonUrl%3Dhttps%3A%2F%2F%2F%2Fhorizon-testnet.stellar.org%26rpcUrl%3Dhttps%3A%2F%2F%2F%2Fsoroban-testnet.stellar.org%26passphrase%3DTest%2520SDF%2520Network%2520%2F%3B%2520September%25202015%3B%26transaction%24build%24classic%24operations%40%24operation_type%3Dpayment%26params%24destination%3DMAFGI4PPDOPTUBVQUFFC6DEX7EP5V6CXHONBNABOZBCV2QTG4GWFCAAAAAAAAAAAAHVGS%26asset%24code%3D%26issuer%3D%26type%3Dnative%3B%26amount%3D5%3B%26source_account%3D%3B%3B%3B%26soroban%24operation%24params%40%3B%3B%3B%26params%24source_account%3DGAFGI4PPDOPTUBVQUFFC6DEX7EP5V6CXHONBNABOZBCV2QTG4GWFCDVE%26seq_num%3D3631072726220801%26memo%3Dnone%3B%26isValid%24params%3Atrue%26operations%3Atrue%3B%3B%26sign%24activeView%3Doverview%26importXdr%3DAAAAAgAAAAAKZHHvG586BrChSi8Ml%2F%2Fkf2vhXO5oWgC7IRV1CZuGsUQAAAGQADOZxAAAAAQAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAQAAAQAAAAAAAAAAAQpkce8bnzoGsKFKLwyX%2BR%2F%2Fa%2BFc7mhaALshFXUJm4axRAAAAAAAAAAAC%2BvCAAAAAAAAAAAA%3D%3B%26simulate%24triggerOnLaunch%3Afalse%3B%3B%26xdr%24blob%3DAAAAAgAAAAAKZHHvG586BrChSi8Ml%2F%2Fkf2vhXO5oWgC7IRV1CZuGsUQAAAGQADOZxAAAAAQAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAQAAAQAAAAAAAAAAAQpkce8bnzoGsKFKLwyX%2BR%2F%2Fa%2BFc7mhaALshFXUJm4axRAAAAAAAAAAAC%2BvCAAAAAAAAAAAFm4axRAAAAQCmlJhCSS%2BQUAg4pmJye1AgVTeZCPcYmLkeF4%2F%2FTuKJ6QXtPjQNSf%2F%2FoeQsVOznBaoTZXUiRUr8YVZQKb4OMVnWws%3D%26jsonString%3D%257B%250A%2520%2520%2522tx%2522%3A%2520%257B%250A%2520%2520%2520%2520%2522tx%2522%3A%2520%257B%250A%2520%2520%2520%2520%2520%2520%2522source_account%2522%3A%2520%2522GAFGI4PPDOPTUBVQUFFC6DEX7EP5V6CXHONBNABOZBCV2QTG4GWFCDVE%2522%2C%250A%2520%2520%2520%2520%2520%2520%2522fee%2522%3A%2520100%2C%250A%2520%2520%2520%2520%2520%2520%2522seq_num%2522%3A%25203631072726220801%2C%250A%2520%2520%2520%2520%2520%2520%2522cond%2522%3A%2520%257B%250A%2520%2520%2520%2520%2520%2520%2520%2520%2522time%2522%3A%2520%257B%250A%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2522min_time%2522%3A%25200%2C%250A%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2522max_time%2522%3A%25200%250A%2520%2520%2520%2520%2520%2520%2520%2520%257D%250A%2520%2520%2520%2520%2520%2520%257D%2C%250A%2520%2520%2520%2520%2520%2520%2522memo%2522%3A%2520%2522none%2522%2C%250A%2520%2520%2520%2520%2520%2520%2522operations%2522%3A%2520%255B%250A%2520%2520%2520%2520%2520%2520%2520%2520%257B%250A%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2522source_account%2522%3A%2520null%2C%250A%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2522body%2522%3A%2520%257B%250A%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2522payment%2522%3A%2520%257B%250A%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2522destination%2522%3A%2520%2522MAFGI4PPDOPTUBVQUFFC6DEX7EP5V6CXHONBNABOZBCV2QTG4GWFCAAAAAAAAAAAAHVGS%2522%2C%250A%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2522asset%2522%3A%2520%2522native%2522%2C%250A%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2522amount%2522%3A%252050000000%250A%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%257D%250A%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%257D%250A%2520%2520%2520%2520%2520%2520%2520%2520%257D%250A%2520%2520%2520%2520%2520%2520%255D%2C%250A%2520%2520%2520%2520%2520%2520%2522ext%2522%3A%2520%2522v0%2522%250A%2520%2520%2520%2520%257D%2C%250A%2520%2520%2520%2520%2522signatures%2522%3A%2520%255B%250A%2520%2520%2520%2520%2520%2520%257B%250A%2520%2520%2520%2520%2520%2520%2520%2520%2522hint%2522%3A%2520%252266e1ac51%2522%2C%250A%2520%2520%2520%2520%2520%2520%2520%2520%2522signature%2522%3A%2520%252229a52610924be414020e29989c9ed408154de6423dc6262e4785e3f4ee289e905ed3e340d49ffe8790b153b39c16a84d95d489152bf1855940a6f838c5675b0b%2522%250A%2520%2520%2520%2520%2520%2520%257D%250A%2520%2520%2520%2520%255D%250A%2520%2520%257D%250A%257D%3B%26smartContracts%24explorer%24contractId%3DCCAXJGTAW77JQS4TFLOP246H7YVQDFFRP3MMARJ75XIQ64FWJYGS32IM%3B%3B&dr=https%3A%2F%2Flaboratory-pr1341.previews.kube001.services.stellar-ops.com%2Fsmart-contracts%2Fcontract-list%3F%24%3Dnetwork%24id%3Dtestnet%26label%3DTestnet%26horizonUrl%3Dhttps%3A%2F%2F%2F%2Fhorizon-testnet.stellar.org%26rpcUrl%3Dhttps%3A%2F%2F%2F%2Fsoroban-testnet.stellar.org%26passphrase%3DTest%2520SDF%2520Network%2520%2F%3B%2520September%25202015%3B%26transaction%24build%24classic%24operations%40%24operation_type%3Dpayment%26params%24destination%3DMAFGI4PPDOPTUBVQUFFC6DEX7EP5V6CXHONBNABOZBCV2QTG4GWFCAAAAAAAAAAAAHVGS%26asset%24code%3D%26issuer%3D%26type%3Dnative%3B%26amount%3D5%3B%26source_account%3D%3B%3B%3B%26soroban%24operation%24params%40%3B%3B%3B%26params%24source_account%3DGAFGI4PPDOPTUBVQUFFC6DEX7EP5V6CXHONBNABOZBCV2QTG4GWFCDVE%26seq_num%3D3631072726220801%26memo%3Dnone%3B%26isValid%24params%3Atrue%26operations%3Atrue%3B%3B%26sign%24activeView%3Doverview%26importXdr%3DAAAAAgAAAAAKZHHvG586BrChSi8Ml%2F%2Fkf2vhXO5oWgC7IRV1CZuGsUQAAAGQADOZxAAAAAQAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAQAAAQAAAAAAAAAAAQpkce8bnzoGsKFKLwyX%2BR%2F%2Fa%2BFc7mhaALshFXUJm4axRAAAAAAAAAAAC%2BvCAAAAAAAAAAAA%3D%3B%26simulate%24triggerOnLaunch%3Afalse%3B%3B%26xdr%24blob%3DAAAAAgAAAAAKZHHvG586BrChSi8Ml%2F%2Fkf2vhXO5oWgC7IRV1CZuGsUQAAAGQADOZxAAAAAQAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAQAAAQAAAAAAAAAAAQpkce8bnzoGsKFKLwyX%2BR%2F%2Fa%2BFc7mhaALshFXUJm4axRAAAAAAAAAAAC%2BvCAAAAAAAAAAAFm4axRAAAAQCmlJhCSS%2BQUAg4pmJye1AgVTeZCPcYmLkeF4%2F%2FTuKJ6QXtPjQNSf%2F%2FoeQsVOznBaoTZXUiRUr8YVZQKb4OMVnWws%3D%26jsonString%3D%257B%250A%2520%2520%2522tx%2522%3A%2520%257B%250A%2520%2520%2520%2520%2522tx%2522%3A%2520%257B%250A%2520%2520%2520%2520%2520%2520%2522source_account%2522%3A%2520%2522GAFGI4PPDOPTUBVQUFFC6DEX7EP5V6CXHONBNABOZBCV2QTG4GWFCDVE%2522%2C%250A%2520%2520%2520%2520%2520%2520%2522fee%2522%3A%2520100%2C%250A%2520%2520%2520%2520%2520%2520%2522seq_num%2522%3A%25203631072726220801%2C%250A%2520%2520%2520%2520%2520%2520%2522cond%2522%3A%2520%257B%250A%2520%2520%2520%2520%2520%2520%2520%2520%2522time%2522%3A%2520%257B%250A%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2522min_time%2522%3A%25200%2C%250A%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2522max_time%2522%3A%25200%250A%2520%2520%2520%2520%2520%2520%2520%2520%257D%250A%2520%2520%2520%2520%2520%2520%257D%2C%250A%2520%2520%2520%2520%2520%2520%2522memo%2522%3A%2520%2522none%2522%2C%250A%2520%2520%2520%2520%2520%2520%2522operations%2522%3A%2520%255B%250A%2520%2520%2520%2520%2520%2520%2520%2520%257B%250A%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2522source_account%2522%3A%2520null%2C%250A%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2522body%2522%3A%2520%257B%250A%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2522payment%2522%3A%2520%257B%250A%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2522destination%2522%3A%2520%2522MAFGI4PPDOPTUBVQUFFC6DEX7EP5V6CXHONBNABOZBCV2QTG4GWFCAAAAAAAAAAAAHVGS%2522%2C%250A%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2522asset%2522%3A%2520%2522native%2522%2C%250A%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2522amount%2522%3A%252050000000%250A%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%257D%250A%2520%2520%2520%2520%2520%2520%2520%2520%2520%2520%257D%250A%2520%2520%2520%2520%2520%2520%2520%2520%257D%250A%2520%2520%2520%2520%2520%2520%255D%2C%250A%2520%2520%2520%2520%2520%2520%2522ext%2522%3A%2520%2522v0%2522%250A%2520%2520%2520%2520%257D%2C%250A%2520%2520%2520%2520%2522signatures%2522%3A%2520%255B%250A%2520%2520%2520%2520%2520%2520%257B%250A%2520%2520%2520%2520%2520%2520%2520%2520%2522hint%2522%3A%2520%252266e1ac51%2522%2C%250A%2520%2520%2520%2520%2520%2520%2520%2520%2522signature%2522%3A%2520%252229a52610924be414020e29989c9ed408154de6423dc6262e4785e3f4ee289e905ed3e340d49ffe8790b153b39c16a84d95d489152bf1855940a6f838c5675b0b%2522%250A%2520%2520%2520%2520%2520%2520%257D%250A%2520%2520%2520%2520%255D%250A%2520%2520%257D%250A%257D%3B%3B

@danieldevos90
Copy link

Hi there, here Daniel from Hypersolid. I would recommend to make the solution to be hardcoded; So implement a <script async src="https://www.googletagmanager.com/gtag/js?id=G-XXXXXXX"></script>

<script> window.dataLayer = window.dataLayer || []; function gtag(){ dataLayer.push(arguments); } gtag('js', new Date()); gtag('config', 'G-XXXXXXX', { {{variables}} }); </script> where we push the stripped URL as a page_location event with the full URL; we can then override the page-location send via GTM with this value and make sure the xdr is not send to GA

@danieldevos90
Copy link

danieldevos90 commented May 12, 2025

@quietbits After reviewing the options discussed, I propose the following solution:

- Option 1

Let's implement a custom page path redaction before sending data to GA4:

// In src/metrics/GoogleAnalytics.tsx

import {
  GoogleAnalytics as NextGoogleAnalytics,
  GoogleTagManager,
} from "@next/third-parties/google";
import { usePathname, useSearchParams } from "next/navigation";

const GA_MEASUREMENT_ID = "GTM-KCNDDL3";

// Function to strip sensitive parameters from the URL
const stripSensitiveParams = (pathname, searchParams) => {
  // Create a copy of search params to modify
  const cleanParams = new URLSearchParams();
  
  // Only copy safe parameters (whitelist approach)
  // Example: Only keep "network" parameter
  if (searchParams.has("network")) {
    cleanParams.set("network", searchParams.get("network"));
  }
  
  // Return clean URL path + permitted parameters
  return `${pathname}${cleanParams.toString() ? `?${cleanParams.toString()}` : ''}`;
};

export const GoogleAnalytics = () => {
  const pathname = usePathname();
  const searchParams = useSearchParams();
  
  const isGoogleTrackingEnabled =
    process.env.NEXT_PUBLIC_DISABLE_GOOGLE_ANALYTICS !== "true" &&
    process.env.NODE_ENV === "production";

  if (!isGoogleTrackingEnabled) {
    return null;
  }
  
  // Create safe URL for analytics
  const safePagePath = stripSensitiveParams(pathname, searchParams);

  return (
    <>
      <GoogleTagManager gtmId={GA_MEASUREMENT_ID} />
      <NextGoogleAnalytics 
        gaId={GA_MEASUREMENT_ID} 
        pageViewOptions={{
          page_path: safePagePath,
        }}
      />
    </>
  );
};  

Option 2 Middleware

We could implement a Next.js middleware solution to clean URLs for analytics purposes:

// src/middleware.ts
export function middleware(request: NextRequest) {
  // Your existing middleware code...

  // Add analytics nonce for our custom script
  const analyticsNonce = Buffer.from(crypto.randomUUID()).toString('base64');
  requestHeaders.set('x-analytics-nonce', analyticsNonce);

  // Other middleware logic...
}

// Then in a custom GA script component:
export const AnalyticsScript = () => {
  const pathname = usePathname();
  // Implementation that uses the nonce and only sends safe URL data
}

Option 3 Comprehensive Session Storage Approach
I think we can implement @quietbits' suggestion for a comprehensive solution:

Move application state to session/local storage instead of keeping it in URLs
Add a "Generate sharing link" button when users need to share their current state
When loading a shared link with parameters, store the data in session and redirect to a clean URL

Let me know what you think!

@stellar-jenkins
Copy link

@stellar-jenkins
Copy link

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: Backlog (Not Ready)
Development

Successfully merging this pull request may close these issues.

Add Google Tag Manager to this app
9 participants