blob: cc3c6e7ebab67a47ce0dd3abc41c1c0ef73deb45 [file] [log] [blame]
/// Matches only alphabetic chars
final RegExp alphabeticPattern = RegExp(r'^[A-Za-z]+$');
/// Matches strings that contain alphanumeric chars and underscores
final RegExp alphaNumericPattern = RegExp(r'^[A-Za-z0-9_]+$');
/// Checks that the body of the request being sent to
/// GA4 is within the limitations
///
/// Limitations can be found:
/// https://developers.google.com/analytics/devguides/collection/protocol/ga4/sending-events?client_type=gtag#limitations
void checkBody(Map<String, Object?> body) {
// Ensure we have the correct top level keys
if (!body.keys.contains('client_id')) {
throw AnalyticsException('client_id missing from top level keys');
}
if (!body.keys.contains('events')) {
throw AnalyticsException('events missing from top level keys');
}
if (!body.keys.contains('user_properties')) {
throw AnalyticsException('user_properties missing from top level keys');
}
final events = body['events'] as List;
final userProperties = body['user_properties'] as Map<String, Object?>;
// GA4 Limitation:
// Requests can have a maximum of 25 events
if (events.length > 25) {
throw AnalyticsException('25 is the max number of events');
}
// Checks for each event object
for (var eventMap in events.cast<Map<String, Object?>>()) {
final eventName = eventMap['name'] as String;
// GA4 Limitation:
// Event names must be 40 characters or fewer, may only contain
// alpha-numeric characters and underscores, and must start
// with an alphabetic character
if (eventName.length > 40) {
throw AnalyticsException('Limit event names to 40 chars or less');
}
if (!alphaNumericPattern.hasMatch(eventName)) {
throw AnalyticsException(
'Event name can only have alphanumeric chars and underscores');
}
if (!alphabeticPattern.hasMatch(eventName[0])) {
throw AnalyticsException('Event name first char must be alphabetic char');
}
final eventParams = eventMap['params'] as Map<String, Object?>;
// GA4 Limitation:
// Events can have a maximum of 25 parameters
if (eventParams.length > 25) {
throw AnalyticsException('Limit params for each event to less than 25');
}
// Loop through each of the event parameters
for (var entry in eventParams.entries) {
final key = entry.key;
final value = entry.value;
// GA4 Limitation:
// Ensure that each value for the event params is one
// of the following types:
// `String`, `int`, `double`, or `bool`
if (!(value is String ||
value is int ||
value is double ||
value is bool)) {
throw AnalyticsException(
'Values for event params have to be String, int, double, or bool');
}
// GA4 Limitation:
// Parameter names (including item parameters) must be 40 characters
// or fewer, may only contain alpha-numeric characters and underscores,
// and must start with an alphabetic character
if (key.length > 40) {
throw AnalyticsException('Limit event param names to 40 chars or less');
}
if (!alphaNumericPattern.hasMatch(key)) {
throw AnalyticsException(
'Event param name can only have alphanumeric chars and underscores',
);
}
if (!alphabeticPattern.hasMatch(key[0])) {
throw AnalyticsException(
'Event param name first char must be alphabetic char');
}
// GA4 Limitation:
// Parameter values (including item parameter values) must be 100
// characters or fewer
if (value.runtimeType == String) {
value as String;
if (value.length > 100) {
throw AnalyticsException(
'Limit characters in event param value to 100 chars or less');
}
}
}
}
// GA4 Limitation:
// Events can have a maximum of 25 user properties
if (userProperties.length > 25) {
throw AnalyticsException('Limit user properties to 25 or less');
}
// Checks for each user property item
for (var entry in userProperties.entries) {
final key = entry.key;
final value = entry.value as Map<String, Object?>;
// GA4 Limitation:
// User property names must be 24 characters or fewer
if (key.length > 24) {
throw AnalyticsException('Limit user property names to 24 chars or less');
}
// GA4 Limitation:
// User property values must be 36 characters or fewer
final userPropValue = value['value'];
if (userPropValue is String && userPropValue.length > 36) {
throw AnalyticsException(
'Limit user property values to 36 chars or less');
}
}
}
class AnalyticsException implements Exception {
final String message;
AnalyticsException(this.message);
}