How to change `userTraits` after the user logout and login with another account
The goal is to change the user traits when the user logout from his account (for example user1) and login into another account (for example user2) when this happend the same traits of the previous user is used, the only way to reset it is to close and reopen the app
How i identify the user
When the app boots or after a successful login I execute this code
userTraits = UserTraits(
name: user.name,
phone: user.phone,
);
segment.identify(
userId: user.id.toString(),
userTraits: userTraits,
);
this code works fine but once, when something changes related to the user (logout and login with different account), re-excuting this not affecting the traits, the only way is to close and reopen the app to be able to set the traits to the new data, how to change the user traits when needed?
What I have tried to achieve this
I have tried all of these in my logout method but failed
-
use
segment.reset(); -
re-identify the user with null user traits values,
segment.identify(
userId: user.id.toString(),
userTraits: null,
);
- re-identify the user with user traits with null values,
userTraits = UserTraits(
name: null,
phone: null,
);
segment.identify(
userId: user.id.toString(),
userTraits: userTraits,
);
as mentioned before, recalling this code with the new user data not affecting his traits
userTraits = UserTraits(
name: user.name,
phone: user.phone,
);
segment.identify(
userId: user.id.toString(),
userTraits: userTraits,
);
Hi @taham8875 thank you for your report. I did this exercise:
- I press
User 1button and set a new userTraits. - I press
User 2button and show the same userTraits that button 'User 1'. - I press
Resetbutton and clear userTraits. - I press
User 2button and it display the userTraits with 'null' value.
Maybe is a simple example but you can have an idea about how you need organize the flow execution of your code.
@edsonjab
I tried all of this, unfortunately, still not working
Oh wow, shocking, no one from Segment has chimed in on this yet. I encountered the same issue and couldn't find anything that provided predictable behavior. From what I can tell, there's a bug in how user traits are saved and updated. I found that using Segment's plugin system gives better control over user traits and other fields. https://segment.com/docs/connections/sources/catalog/libraries/mobile/flutter/#plugin-architecture
These plugins, written by Segment, helped me better understand how to use them. Much more than their documentation did. https://github.com/segmentio/analytics_flutter/blob/main/packages/core/lib/plugins/inject_context.dart https://github.com/segmentio/analytics_flutter/blob/main/packages/core/lib/plugins/inject_user_info.dart
Hello @chrisdlangham @taham8875 ,
I created a small Proof of concept app as an attempt to reproduce this issue but cannot reproduce the issue. I am posting the code below.
Proof of concept:
-
Create a Flutter demo project to reproduce the issue.
-
Add following line to AndroidManifest.xml:
<uses-permission android:name="android.permission.INTERNET"/>and build the app. -
If you get error about NDK version, change ndkVersion in build.gradle.kts
android {
namespace = "com.example.flutter_app"
compileSdk = flutter.compileSdkVersion
ndkVersion = "27.0.12077973"
- Delete the default code in /flutter_app/lib/main.dart and paste following code in it:
import 'package:flutter/material.dart';
import 'package:segment_analytics/client.dart';
import 'package:segment_analytics/event.dart';
import 'package:segment_analytics/state.dart';
// Initialize the Segment client with your write key
final analytics = createClient(
Configuration(
'Your_Write_Key',
debug: true, // Enable debug logs
),
);
void main() async {
WidgetsFlutterBinding.ensureInitialized();
runApp(MyApp());
}
class User {
final String id;
final String name;
final String phone;
User({required this.id, required this.name, required this.phone});
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Segment Trait Reset Demo',
home: UserSwitcher(),
);
}
}
class UserSwitcher extends StatefulWidget {
@override
_UserSwitcherState createState() => _UserSwitcherState();
}
class _UserSwitcherState extends State<UserSwitcher> {
User? currentUser;
final user1 = User(id: '1', name: 'Alice', phone: '111-111');
final user2 = User(id: '2', name: 'Bob', phone: '222-222');
void login(User user) async {
print('Logging in as ${user.name}');
await analytics.identify(
userId: user.id,
userTraits: UserTraits(
name: user.name,
phone: user.phone,
),
);
setState(() {
currentUser = user;
});
}
void logout() async {
print('Logging out...');
await analytics.reset();
setState(() {
currentUser = null;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Segment Trait Reset Demo'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
if (currentUser == null) ...[
ElevatedButton(
onPressed: () => login(user1),
child: Text('Login as Alice'),
),
ElevatedButton(
onPressed: () => login(user2),
child: Text('Login as Bob'),
),
] else ...[
Text('Logged in as: ${currentUser!.name}'),
SizedBox(height: 16),
ElevatedButton(
onPressed: logout,
child: Text('Logout'),
),
]
],
),
),
);
}
}
- Run the app on emulator device. (We have tested it on Android 14 and 15)
- Click "Login as Alice" – traits should send Alice’s info to Segment.
- Click "Logout" – this calls analytics.reset().
- Click "Login as Bob" – Bob’s traits should now replace Alice’s.
- Use Segment’s Debugger to verify what's sent.