We're investigating survey responses being recorded as Anonymous in our Formbricks workspace, and suspect (not confirmed) a race between identification and survey rendering: setUserId()/setAttribute() queue into UpdateQueue and only reach the backend once commit()'s async /user POST resolves, but SurveyManager.track() doesn't wait on that.
From what we can tell, contactId is read once into the survey's WebView payload at render time (FormbricksViewModel.getJson()) and never refreshed afterward — so if identification hasn't landed at that moment, the response looks to be permanently unassociated regardless of how the user answers.
We can't fully confirm this from our side: the native SDK doesn't expose any way to observe display/response/finished events or a responseId from the host app (WebAppInterface.WebAppCallback looks like it could carry this, but it's internal and payload-less). A public listener surfacing surveyId/responseId/whether the response is tied to an identified contact would let us verify this ourselves instead of guessing.
This looks like the same race you already fixed in the JS SDK (#7498 , waitForPendingWork() gate before renderWidget). Would you like us to put up a PR porting an equivalent gate to SurveyManager.track() here (and flag the same for formbricks-ios, which shares the UpdateQueue pattern)?
We're investigating survey responses being recorded as Anonymous in our Formbricks workspace, and suspect (not confirmed) a race between identification and survey rendering:
setUserId()/setAttribute()queue intoUpdateQueueand only reach the backend oncecommit()'s async/userPOST resolves, butSurveyManager.track()doesn't wait on that.From what we can tell,
contactIdis read once into the survey's WebView payload at render time (FormbricksViewModel.getJson()) and never refreshed afterward — so if identification hasn't landed at that moment, the response looks to be permanently unassociated regardless of how the user answers.We can't fully confirm this from our side: the native SDK doesn't expose any way to observe display/response/finished events or a
responseIdfrom the host app (WebAppInterface.WebAppCallbacklooks like it could carry this, but it's internal and payload-less). A public listener surfacingsurveyId/responseId/whether the response is tied to an identified contact would let us verify this ourselves instead of guessing.This looks like the same race you already fixed in the JS SDK (#7498 ,
waitForPendingWork()gate beforerenderWidget). Would you like us to put up a PR porting an equivalent gate toSurveyManager.track()here (and flag the same forformbricks-ios, which shares theUpdateQueuepattern)?