0

[FedCM] Add account sign-up/sign-in state to metrics

After fetching accounts from IdP, knowing whether the API is for sign-up
or sign-in users can help us better understand user expectation and how
FedCM performs differently. e.g. CTR for sign-in users should be higher
than sign-up users but it should be quantifiable.

UKM review: https://docs.google.com/document/d/1hP0O1CcDgLk3RB_jlYOQtl9xQj9woFBcBpaJy4mFK9Q/edit?resourcekey=0-u4gaHookWBYkgngUxTiDxA&disco=AAABfDiVXoY

Bug: 397455375
Change-Id: Icf968e429f723b45f409661a2465a5cdc7ae1b1c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6311101
Commit-Queue: Yi Gu <yigu@chromium.org>
Reviewed-by: Christian Biesinger <cbiesinger@chromium.org>
Reviewed-by: Sun Yueru <yrsun@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1427257}
This commit is contained in:
Yi Gu
2025-03-03 11:00:29 -08:00
committed by Chromium LUCI CQ
parent a5b49ce36b
commit 17c501232f
6 changed files with 66 additions and 4 deletions

@ -275,7 +275,8 @@ void FedCmMetrics::RecordRequestTokenStatus(
std::optional<FedCmUseOtherAccountResult> use_other_account_result,
std::optional<FedCmVerifyingDialogResult> verifying_dialog_result,
FedCmThirdPartyCookiesStatus tpc_status,
const FedCmRequesterFrameType& requester_frame_type) {
const FedCmRequesterFrameType& requester_frame_type,
std::optional<bool> has_signin_account) {
// The following check is to avoid double recording in the following scenario:
// 1. The request has failed but we have not yet rejected the promise, e.g.
// when the API is disabled. We record a metric immediately but only post a
@ -313,6 +314,9 @@ void FedCmMetrics::RecordRequestTokenStatus(
static_cast<int>(*verifying_dialog_result));
}
ukm_builder.SetFrameType(static_cast<int>(requester_frame_type));
if (has_signin_account.has_value()) {
ukm_builder.SetHasSigninAccount(*has_signin_account);
}
ukm_builder.SetFedCmSessionID(session_id_);
ukm_builder.Record(ukm::UkmRecorder::Get());
};
@ -350,6 +354,10 @@ void FedCmMetrics::RecordRequestTokenStatus(
base::UmaHistogramEnumeration("Blink.FedCm.VerifyingDialogResult",
*verifying_dialog_result);
}
if (has_signin_account.has_value()) {
base::UmaHistogramBoolean("Blink.FedCm.HasSigninAccount",
*has_signin_account);
}
// Reset the `session_id_`. We expect no more metrics from this API call.
session_id_ = -1;
}

@ -387,7 +387,8 @@ class CONTENT_EXPORT FedCmMetrics {
std::optional<FedCmUseOtherAccountResult> use_other_account_result,
std::optional<FedCmVerifyingDialogResult> verifying_dialog_result,
FedCmThirdPartyCookiesStatus tpc_status,
const FedCmRequesterFrameType& requester_frame_type);
const FedCmRequesterFrameType& requester_frame_type,
std::optional<bool> has_signin_account);
// Records whether user sign-in states between IDP and browser match.
void RecordSignInStateMatchStatus(const GURL& provider,

@ -784,7 +784,8 @@ void FederatedAuthRequestImpl::RequestToken(
? FedCmThirdPartyCookiesStatus::kEnabledInSettings
: FedCmThirdPartyCookiesStatus::kDisabledInSettings,
webid::ComputeRequesterFrameType(render_frame_host(), origin(),
GetEmbeddingOrigin()));
GetEmbeddingOrigin()),
/*has_signin_account=*/std::nullopt);
AddDevToolsIssue(
blink::mojom::FederatedAuthRequestResult::kTooManyRequests);
@ -2985,6 +2986,18 @@ void FederatedAuthRequestImpl::CompleteRequest(
: FedCmVerifyingDialogResult::kDestroyAutoReauthn;
}
std::optional<bool> has_signin_account;
// Note: accounts_ does not include the ones that got filtered out. In case
// that all accounts are filtered out, we'd show the mismatch UI and skip
// recording the account status on the mismatch UI.
for (const auto& account : accounts_) {
has_signin_account = false;
if (account->login_state == LoginState::kSignIn) {
has_signin_account = true;
break;
}
}
fedcm_metrics_->RecordRequestTokenStatus(
*token_status, mediation_requirement_, idp_order_, num_idps_mismatch,
selected_idp_config_url, rp_mode_, use_other_account_result,
@ -2993,7 +3006,8 @@ void FederatedAuthRequestImpl::CompleteRequest(
? FedCmThirdPartyCookiesStatus::kEnabledInSettings
: FedCmThirdPartyCookiesStatus::kDisabledInSettings,
webid::ComputeRequesterFrameType(render_frame_host(), origin(),
GetEmbeddingOrigin()));
GetEmbeddingOrigin()),
has_signin_account);
}
if (result == FederatedAuthRequestResult::kSuccess) {

@ -2156,6 +2156,8 @@ TEST_F(FederatedAuthRequestImplTest, LoginStateShouldBeSignUpForFirstTimeUser) {
RunAuthTest(kDefaultRequestParameters, kExpectationSuccess,
kConfigurationValid);
EXPECT_EQ(LoginState::kSignUp, all_accounts_for_display()[0]->login_state);
histogram_tester_.ExpectUniqueSample("Blink.FedCm.HasSigninAccount", false,
1);
}
TEST_F(FederatedAuthRequestImplTest, LoginStateShouldBeSignInForReturningUser) {
@ -2185,6 +2187,8 @@ TEST_F(FederatedAuthRequestImplTest, LoginStateShouldBeSignInForReturningUser) {
histogram_tester_.ExpectUniqueTimeSample(
"Blink.FedCm.Timing.ShowAccountsDialogBreakdown.ClientMetadataFetch",
base::TimeDelta(), 1);
histogram_tester_.ExpectUniqueSample("Blink.FedCm.HasSigninAccount", true, 1);
}
TEST_F(FederatedAuthRequestImplTest,
@ -5449,6 +5453,7 @@ TEST_F(FederatedAuthRequestImplTest, LoginHintSingleAccountNoMatch) {
RunAuthTest(parameters, expectations, configuration);
EXPECT_TRUE(DidFetch(FetchedEndpoint::ACCOUNTS));
EXPECT_FALSE(did_show_accounts_dialog());
ExpectNoUKMPresence("HasSigninAccount");
histogram_tester_.ExpectUniqueSample(
"Blink.FedCm.LoginHint.NumMatchingAccounts",
@ -6529,6 +6534,7 @@ TEST_F(FederatedAuthRequestImplTest, MismatchDialogShownMetric) {
FedCmMetrics::MismatchDialogType::kFirstWithoutHints, 1);
ExpectUKMPresence("MismatchDialogShown");
ExpectNoUKMPresence("AccountsDialogShown");
ExpectNoUKMPresence("HasSigninAccount");
CheckAllFedCmSessionIDs();
}
@ -7415,6 +7421,8 @@ TEST_F(FederatedAuthRequestImplTest,
EXPECT_EQ(all_accounts_for_display()[2]->login_state, LoginState::kSignUp);
EXPECT_EQ(all_accounts_for_display()[2]->browser_trusted_login_state,
LoginState::kSignUp);
ExpectUkmValue("HasSigninAccount", true);
}
// Test that IdP claimed SignIn does not affect browser observed SignUp.

@ -1562,6 +1562,19 @@ chromium-metrics-reviews@google.com.
</summary>
</histogram>
<histogram name="Blink.FedCm.HasSigninAccount" enum="BooleanYesNo"
expires_after="2025-08-12">
<owner>yigu@chromium.org</owner>
<owner>web-identity-eng@google.com</owner>
<summary>
Records whether a user is signing up with the API. Records once per
successful account fetch from the IdP server after the accounts filtering.
If there are multiple accounts, record the user as sign-in if IdP claims at
least one of the accounts is sign-in. If an IdP does not share the user's
sign-in state, record the state stored in the browser.
</summary>
</histogram>
<histogram name="Blink.FedCm.IdentityProvidersCount" units="count"
expires_after="2025-08-12">
<owner>npm@chromium.org</owner>

@ -3770,6 +3770,15 @@ be describing additional metrics about the same event.
category.
</summary>
</metric>
<metric name="HasSigninAccount" enum="Boolean">
<summary>
Records whether a user is signing up with the API. Records once per
successful account fetch from the IdP server after the accounts filtering.
If there are multiple accounts, record the user as sign-in if IdP claims
at least one of the accounts is sign-in. If an IdP does not share the
user's sign-in state, record the state stored in the browser.
</summary>
</metric>
<metric name="LoginHint.NumMatchingAccounts" enum="FedCmNumAccounts">
<summary>
Records the number of accounts that match a login hint. Records at the
@ -4052,6 +4061,15 @@ be describing additional metrics about the same event.
category.
</summary>
</metric>
<metric name="HasSigninAccount" enum="Boolean">
<summary>
Records whether a user is signing up with the API. Records once per
successful account fetch from the IdP server after the accounts filtering.
If there are multiple accounts, record the user as sign-in if IdP claims
at least one of the accounts is sign-in. If an IdP does not share the
user's sign-in state, record the state stored in the browser.
</summary>
</metric>
<metric name="MismatchDialogShown" enum="BooleanHit">
<summary>
Records a 1 each time a mismatch dialog is shown.