diff --git a/optimizely/decision_service.py b/optimizely/decision_service.py
index 52e9d02b..98060e8e 100644
--- a/optimizely/decision_service.py
+++ b/optimizely/decision_service.py
@@ -413,39 +413,6 @@ def get_variation_for_rollout(self, project_config, rollout, user_id, attributes
 
         return Decision(None, None, enums.DecisionSources.ROLLOUT), decide_reasons
 
-    def get_experiment_in_group(self, project_config, group, bucketing_id):
-        """ Determine which experiment in the group the user is bucketed into.
-
-    Args:
-      project_config: Instance of ProjectConfig.
-      group: The group to bucket the user into.
-      bucketing_id: ID to be used for bucketing the user.
-
-    Returns:
-      Experiment if the user is bucketed into an experiment in the specified group. None otherwise
-      and array of log messages representing decision making.
-    """
-        decide_reasons = []
-        experiment_id = self.bucketer.find_bucket(
-            project_config, bucketing_id, group.id, group.trafficAllocation)
-        if experiment_id:
-            experiment = project_config.get_experiment_from_id(experiment_id)
-            if experiment:
-                message = 'User with bucketing ID "%s" is in experiment %s of group %s.' % \
-                    (bucketing_id, experiment.key, group.id)
-                self.logger.info(
-                    message
-                )
-                decide_reasons.append(message)
-                return experiment, decide_reasons
-        message = 'User with bucketing ID "%s" is not in any experiments of group %s.' % (bucketing_id, group.id)
-        self.logger.info(
-            message
-        )
-        decide_reasons.append(message)
-
-        return None, decide_reasons
-
     def get_variation_for_feature(self, project_config, feature, user_id, attributes=None, ignore_user_profile=False):
         """ Returns the experiment/variation the user is bucketed in for the given feature.
 
@@ -462,31 +429,18 @@ def get_variation_for_feature(self, project_config, feature, user_id, attributes
         decide_reasons = []
         bucketing_id, reasons = self._get_bucketing_id(user_id, attributes)
         decide_reasons += reasons
-        # First check if the feature is in a mutex group
-        if feature.groupId:
-            group = project_config.get_group(feature.groupId)
-            if group:
-                experiment, reasons = self.get_experiment_in_group(project_config, group, bucketing_id)
-                decide_reasons += reasons
-                if experiment and experiment.id in feature.experimentIds:
+
+        # Check if the feature flag is under an experiment and the the user is bucketed into one of these experiments
+        if feature.experimentIds:
+            # Evaluate each experiment ID and return the first bucketed experiment variation
+            for experiment in feature.experimentIds:
+                experiment = project_config.get_experiment_from_id(experiment)
+                if experiment:
                     variation, variation_reasons = self.get_variation(
                         project_config, experiment, user_id, attributes, ignore_user_profile)
                     decide_reasons += variation_reasons
                     if variation:
                         return Decision(experiment, variation, enums.DecisionSources.FEATURE_TEST), decide_reasons
-            else:
-                self.logger.error(enums.Errors.INVALID_GROUP_ID.format('_get_variation_for_feature'))
-
-        # Next check if the feature is being experimented on
-        elif feature.experimentIds:
-            # If an experiment is not in a group, then the feature can only be associated with one experiment
-            experiment = project_config.get_experiment_from_id(feature.experimentIds[0])
-            if experiment:
-                variation, variation_reasons = self.get_variation(
-                    project_config, experiment, user_id, attributes, ignore_user_profile)
-                decide_reasons += variation_reasons
-                if variation:
-                    return Decision(experiment, variation, enums.DecisionSources.FEATURE_TEST), decide_reasons
 
         # Next check if user is part of a rollout
         if feature.rolloutId:
diff --git a/optimizely/project_config.py b/optimizely/project_config.py
index 77b89e67..c0004495 100644
--- a/optimizely/project_config.py
+++ b/optimizely/project_config.py
@@ -128,13 +128,6 @@ def __init__(self, datafile, logger, error_handler):
                 # Add this experiment in experiment-feature map.
                 self.experiment_feature_map[exp_id] = [feature.id]
 
-                experiment_in_feature = self.experiment_id_map[exp_id]
-                # Check if any of the experiments are in a group and add the group id for faster bucketing later on
-                if experiment_in_feature.groupId:
-                    feature.groupId = experiment_in_feature.groupId
-                    # Experiments in feature can only belong to one mutex group
-                    break
-
     @staticmethod
     def _generate_key_map(entity_list, key, entity_class):
         """ Helper method to generate map from key to entity object for given list of dicts.
diff --git a/tests/base.py b/tests/base.py
index 254be7c5..83506c8f 100644
--- a/tests/base.py
+++ b/tests/base.py
@@ -196,6 +196,78 @@ def setUp(self, config_dict='config_dict'):
                         },
                     ],
                 },
+                {
+                    'key': 'test_experiment3',
+                    'status': 'Running',
+                    'layerId': '6',
+                    "audienceConditions": [
+                        "or",
+                        "11160"
+                    ],
+                    'audienceIds': ['11160'],
+                    'id': '111134',
+                    'forcedVariations': {},
+                    'trafficAllocation': [
+                        {'entityId': '222239', 'endOfRange': 2500},
+                        {'entityId': '', 'endOfRange': 5000},
+                        {'entityId': '', 'endOfRange': 7500},
+                        {'entityId': '', 'endOfRange': 10000}
+                    ],
+                    'variations': [
+                        {
+                            'id': '222239',
+                            'key': 'control',
+                            'variables': [],
+                        }
+                    ],
+                },
+                {
+                    'key': 'test_experiment4',
+                    'status': 'Running',
+                    'layerId': '7',
+                    "audienceConditions": [
+                        "or",
+                        "11160"
+                    ],
+                    'audienceIds': ['11160'],
+                    'id': '111135',
+                    'forcedVariations': {},
+                    'trafficAllocation': [
+                        {'entityId': '222240', 'endOfRange': 5000},
+                        {'entityId': '', 'endOfRange': 7500},
+                        {'entityId': '', 'endOfRange': 10000}
+                    ],
+                    'variations': [
+                        {
+                            'id': '222240',
+                            'key': 'control',
+                            'variables': [],
+                        }
+                    ],
+                },
+                {
+                    'key': 'test_experiment5',
+                    'status': 'Running',
+                    'layerId': '8',
+                    "audienceConditions": [
+                        "or",
+                        "11160"
+                    ],
+                    'audienceIds': ['11160'],
+                    'id': '111136',
+                    'forcedVariations': {},
+                    'trafficAllocation': [
+                        {'entityId': '222241', 'endOfRange': 7500},
+                        {'entityId': '', 'endOfRange': 10000}
+                    ],
+                    'variations': [
+                        {
+                            'id': '222241',
+                            'key': 'control',
+                            'variables': [],
+                        }
+                    ],
+                },
             ],
             'groups': [
                 {
@@ -239,6 +311,72 @@ def setUp(self, config_dict='config_dict'):
                         {'entityId': '32222', "endOfRange": 3000},
                         {'entityId': '32223', 'endOfRange': 7500},
                     ],
+                },
+                {
+                    'id': '19229',
+                    'policy': 'random',
+                    'experiments': [
+                        {
+                            'id': '42222',
+                            'key': 'group_2_exp_1',
+                            'status': 'Running',
+                            "audienceConditions": [
+                                "or",
+                                "11160"
+                            ],
+                            'audienceIds': ['11160'],
+                            'layerId': '211183',
+                            'variations': [
+                                {'key': 'var_1', 'id': '38901'},
+                            ],
+                            'forcedVariations': {},
+                            'trafficAllocation': [
+                                {'entityId': '38901', 'endOfRange': 10000}
+                            ],
+                        },
+                        {
+                            'id': '42223',
+                            'key': 'group_2_exp_2',
+                            'status': 'Running',
+                            "audienceConditions": [
+                                "or",
+                                "11160"
+                            ],
+                            'audienceIds': ['11160'],
+                            'layerId': '211184',
+                            'variations': [
+                                {'key': 'var_1', 'id': '38905'}
+                            ],
+                            'forcedVariations': {},
+                            'trafficAllocation': [
+                                {'entityId': '38905', 'endOfRange': 10000}
+                            ],
+                        },
+                        {
+                            'id': '42224',
+                            'key': 'group_2_exp_3',
+                            'status': 'Running',
+                            "audienceConditions": [
+                                "or",
+                                "11160"
+                            ],
+                            'audienceIds': ['11160'],
+                            'layerId': '211185',
+                            'variations': [
+                                {'key': 'var_1', 'id': '38906'}
+                            ],
+                            'forcedVariations': {},
+                            'trafficAllocation': [
+                                {'entityId': '38906', 'endOfRange': 10000}
+                            ],
+                        }
+                    ],
+                    'trafficAllocation': [
+                        {'entityId': '42222', "endOfRange": 2500},
+                        {'entityId': '42223', 'endOfRange': 5000},
+                        {'entityId': '42224', "endOfRange": 7500},
+                        {'entityId': '', 'endOfRange': 10000},
+                    ],
                 }
             ],
             'attributes': [{'key': 'test_attribute', 'id': '111094'}],
@@ -255,6 +393,12 @@ def setUp(self, config_dict='config_dict'):
                     '{"name": "test_attribute", "type": "custom_attribute", "value": "test_value_2"}]]]',
                     'id': '11159',
                 },
+                {
+                    'name': 'Test attribute users 3',
+                    'conditions': "[\"and\", [\"or\", [\"or\", {\"match\": \"exact\", \"name\": \
+                        \"experiment_attr\", \"type\": \"custom_attribute\", \"value\": \"group_experiment\"}]]]",
+                    'id': '11160',
+                }
             ],
             'rollouts': [
                 {'id': '201111', 'experiments': []},
@@ -364,6 +508,20 @@ def setUp(self, config_dict='config_dict'):
                     'rolloutId': '211111',
                     'variables': [],
                 },
+                {
+                    'id': '91115',
+                    'key': 'test_feature_in_exclusion_group',
+                    'experimentIds': ['42222', '42223', '42224'],
+                    'rolloutId': '211111',
+                    'variables': [],
+                },
+                {
+                    'id': '91116',
+                    'key': 'test_feature_in_multiple_experiments',
+                    'experimentIds': ['111134', '111135', '111136'],
+                    'rolloutId': '211111',
+                    'variables': [],
+                },
             ],
         }
 
diff --git a/tests/test_config.py b/tests/test_config.py
index e8836471..4bf1f61c 100644
--- a/tests/test_config.py
+++ b/tests/test_config.py
@@ -501,7 +501,7 @@ def test_init__with_v4_datafile(self):
                 '211111',
                 {'number_of_projects': entities.Variable('131', 'number_of_projects', 'integer', '10')},
             ),
-            'test_feature_in_group': entities.FeatureFlag('91113', 'test_feature_in_group', ['32222'], '', {}, '19228'),
+            'test_feature_in_group': entities.FeatureFlag('91113', 'test_feature_in_group', ['32222'], '', {}),
         }
 
         expected_rollout_id_map = {
diff --git a/tests/test_decision_service.py b/tests/test_decision_service.py
index f4023d0a..97fefce7 100644
--- a/tests/test_decision_service.py
+++ b/tests/test_decision_service.py
@@ -1320,9 +1320,6 @@ def test_get_variation_for_feature__returns_variation_for_feature_in_group(self)
             "group_exp_1", "28901"
         )
         with mock.patch(
-            "optimizely.decision_service.DecisionService.get_experiment_in_group",
-            return_value=(self.project_config.get_experiment_from_key("group_exp_1"), []),
-        ) as mock_get_experiment_in_group, mock.patch(
             "optimizely.decision_service.DecisionService.get_variation",
             return_value=(expected_variation, []),
         ) as mock_decision:
@@ -1338,9 +1335,6 @@ def test_get_variation_for_feature__returns_variation_for_feature_in_group(self)
                 variation_received,
             )
 
-        mock_get_experiment_in_group.assert_called_once_with(
-            self.project_config, self.project_config.get_group("19228"), 'test_user')
-
         mock_decision.assert_called_once_with(
             self.project_config,
             self.project_config.get_experiment_from_key("group_exp_1"),
@@ -1349,17 +1343,14 @@ def test_get_variation_for_feature__returns_variation_for_feature_in_group(self)
             False
         )
 
-    def test_get_variation_for_feature__returns_none_for_user_not_in_group(self):
-        """ Test that get_variation_for_feature returns None for
-    user not in group and the feature is not part of a rollout. """
+    def test_get_variation_for_feature__returns_none_for_user_not_in_experiment(self):
+        """ Test that get_variation_for_feature returns None for user not in the associated experiment. """
 
-        feature = self.project_config.get_feature_from_key("test_feature_in_group")
+        feature = self.project_config.get_feature_from_key("test_feature_in_experiment")
 
         with mock.patch(
-            "optimizely.decision_service.DecisionService.get_experiment_in_group",
+            "optimizely.decision_service.DecisionService.get_variation",
             return_value=[None, []],
-        ) as mock_get_experiment_in_group, mock.patch(
-            "optimizely.decision_service.DecisionService.get_variation"
         ) as mock_decision:
             variation_received, _ = self.decision_service.get_variation_for_feature(
                 self.project_config, feature, "test_user"
@@ -1369,16 +1360,21 @@ def test_get_variation_for_feature__returns_none_for_user_not_in_group(self):
                 variation_received,
             )
 
-        mock_get_experiment_in_group.assert_called_once_with(
-            self.project_config, self.project_config.get_group("19228"), "test_user")
-
-        self.assertFalse(mock_decision.called)
-
-    def test_get_variation_for_feature__returns_none_for_user_not_in_experiment(self):
-        """ Test that get_variation_for_feature returns None for user not in the associated experiment. """
+        mock_decision.assert_called_once_with(
+            self.project_config,
+            self.project_config.get_experiment_from_key("test_experiment"),
+            "test_user",
+            None,
+            False
+        )
 
-        feature = self.project_config.get_feature_from_key("test_feature_in_experiment")
+    def test_get_variation_for_feature__returns_none_for_user_in_group_experiment_not_associated_with_feature(
+        self,
+    ):
+        """ Test that if a user is in the mutex group but the experiment is
+    not targeting a feature, then None is returned. """
 
+        feature = self.project_config.get_feature_from_key("test_feature_in_group")
         with mock.patch(
             "optimizely.decision_service.DecisionService.get_variation",
             return_value=[None, []],
@@ -1392,89 +1388,301 @@ def test_get_variation_for_feature__returns_none_for_user_not_in_experiment(self
             )
 
         mock_decision.assert_called_once_with(
-            self.project_config,
-            self.project_config.get_experiment_from_key("test_experiment"),
-            "test_user",
-            None,
-            False
+            self.project_config, self.project_config.get_experiment_from_id("32222"), "test_user", None, False
         )
 
-    def test_get_variation_for_feature__returns_none_for_invalid_group_id(self):
-        """ Test that get_variation_for_feature returns None for unknown group ID. """
+    def test_get_variation_for_feature__returns_variation_for_feature_in_mutex_group_bucket_less_than_2500(
+        self,
+    ):
+        """ Test that if a user is in the mutex group and the user bucket value should be less than 2500."""
 
-        feature = self.project_config.get_feature_from_key("test_feature_in_group")
-        feature.groupId = "aabbccdd"
+        feature = self.project_config.get_feature_from_key("test_feature_in_exclusion_group")
+        expected_experiment = self.project_config.get_experiment_from_key("group_2_exp_1")
+        expected_variation = self.project_config.get_variation_from_id(
+            "group_2_exp_1", "38901"
+        )
+        user_attr = {"experiment_attr": "group_experiment"}
+        with mock.patch(
+            'optimizely.bucketer.Bucketer._generate_bucket_value', return_value=2400) as mock_generate_bucket_value,\
+                mock.patch.object(self.project_config, 'logger') as mock_config_logging:
 
-        with self.mock_decision_logger as mock_decision_service_logging:
             variation_received, _ = self.decision_service.get_variation_for_feature(
-                self.project_config, feature, "test_user"
+                self.project_config, feature, "test_user", user_attr
             )
+
             self.assertEqual(
-                decision_service.Decision(None, None, enums.DecisionSources.ROLLOUT),
+                decision_service.Decision(
+                    expected_experiment,
+                    expected_variation,
+                    enums.DecisionSources.FEATURE_TEST,
+                ),
                 variation_received,
             )
-        mock_decision_service_logging.error.assert_called_once_with(
-            enums.Errors.INVALID_GROUP_ID.format("_get_variation_for_feature")
+
+        mock_config_logging.debug.assert_called_with('Assigned bucket 2400 to user with bucketing ID "test_user".')
+        mock_generate_bucket_value.assert_called_with('test_user42222')
+
+    def test_get_variation_for_feature__returns_variation_for_feature_in_mutex_group_bucket_range_2500_5000(
+        self,
+    ):
+        """ Test that if a user is in the mutex group and the user bucket value should be equal to 2500
+        or less than 5000."""
+
+        feature = self.project_config.get_feature_from_key("test_feature_in_exclusion_group")
+        expected_experiment = self.project_config.get_experiment_from_key("group_2_exp_2")
+        expected_variation = self.project_config.get_variation_from_id(
+            "group_2_exp_2", "38905"
         )
+        user_attr = {"experiment_attr": "group_experiment"}
+        with mock.patch(
+            'optimizely.bucketer.Bucketer._generate_bucket_value', return_value=4000) as mock_generate_bucket_value,\
+                mock.patch.object(self.project_config, 'logger') as mock_config_logging:
 
-    def test_get_variation_for_feature__returns_none_for_user_in_group_experiment_not_associated_with_feature(
+            variation_received, _ = self.decision_service.get_variation_for_feature(
+                self.project_config, feature, "test_user", user_attr
+            )
+            self.assertEqual(
+                decision_service.Decision(
+                    expected_experiment,
+                    expected_variation,
+                    enums.DecisionSources.FEATURE_TEST,
+                ),
+                variation_received,
+            )
+        mock_config_logging.debug.assert_called_with('Assigned bucket 4000 to user with bucketing ID "test_user".')
+        mock_generate_bucket_value.assert_called_with('test_user42223')
+
+    def test_get_variation_for_feature__returns_variation_for_feature_in_mutex_group_bucket_range_5000_7500(
         self,
     ):
-        """ Test that if a user is in the mutex group but the experiment is
-    not targeting a feature, then None is returned. """
+        """ Test that if a user is in the mutex group and the user bucket value should be equal to 5000
+        or less than 7500."""
 
-        feature = self.project_config.get_feature_from_key("test_feature_in_group")
+        feature = self.project_config.get_feature_from_key("test_feature_in_exclusion_group")
+        expected_experiment = self.project_config.get_experiment_from_key("group_2_exp_3")
+        expected_variation = self.project_config.get_variation_from_id(
+            "group_2_exp_3", "38906"
+        )
+        user_attr = {"experiment_attr": "group_experiment"}
 
         with mock.patch(
-            "optimizely.decision_service.DecisionService.get_experiment_in_group",
-            return_value=[self.project_config.get_experiment_from_key("group_exp_2"), []],
-        ) as mock_decision:
+            'optimizely.bucketer.Bucketer._generate_bucket_value', return_value=6500) as mock_generate_bucket_value,\
+                mock.patch.object(self.project_config, 'logger') as mock_config_logging:
+
             variation_received, _ = self.decision_service.get_variation_for_feature(
-                self.project_config, feature, "test_user"
+                self.project_config, feature, "test_user", user_attr
             )
             self.assertEqual(
-                decision_service.Decision(None, None, enums.DecisionSources.ROLLOUT),
+                decision_service.Decision(
+                    expected_experiment,
+                    expected_variation,
+                    enums.DecisionSources.FEATURE_TEST,
+                ),
                 variation_received,
             )
+        mock_config_logging.debug.assert_called_with('Assigned bucket 6500 to user with bucketing ID "test_user".')
+        mock_generate_bucket_value.assert_called_with('test_user42224')
 
-        mock_decision.assert_called_once_with(
-            self.project_config, self.project_config.get_group("19228"), "test_user"
+    def test_get_variation_for_feature__returns_variation_for_rollout_in_mutex_group_bucket_greater_than_7500(
+        self,
+    ):
+        """ Test that if a user is in the mutex group and the user bucket value should be greater than  7500."""
+
+        feature = self.project_config.get_feature_from_key("test_feature_in_exclusion_group")
+        user_attr = {"experiment_attr": "group_experiment"}
+        with mock.patch(
+            'optimizely.bucketer.Bucketer._generate_bucket_value', return_value=8000) as mock_generate_bucket_value,\
+                mock.patch.object(self.project_config, 'logger') as mock_config_logging:
+
+            variation_received, _ = self.decision_service.get_variation_for_feature(
+                self.project_config, feature, "test_user", user_attr
+            )
+            self.assertEqual(
+                decision_service.Decision(
+                    None,
+                    None,
+                    enums.DecisionSources.ROLLOUT,
+                ),
+                variation_received,
+            )
+
+        mock_generate_bucket_value.assert_called_with('test_user211147')
+        mock_config_logging.debug.assert_called_with('Assigned bucket 8000 to user with bucketing ID "test_user".')
+
+    def test_get_variation_for_feature__returns_variation_for_feature_in_experiment_bucket_less_than_2500(
+        self,
+    ):
+        """ Test that if a user is in the non-mutex group and the user bucket value should be less than 2500."""
+
+        feature = self.project_config.get_feature_from_key("test_feature_in_multiple_experiments")
+        expected_experiment = self.project_config.get_experiment_from_key("test_experiment3")
+        expected_variation = self.project_config.get_variation_from_id(
+            "test_experiment3", "222239"
         )
+        user_attr = {"experiment_attr": "group_experiment"}
+
+        with mock.patch(
+            'optimizely.bucketer.Bucketer._generate_bucket_value', return_value=2400) as mock_generate_bucket_value,\
+                mock.patch.object(self.project_config, 'logger') as mock_config_logging:
+
+            variation_received, _ = self.decision_service.get_variation_for_feature(
+                self.project_config, feature, "test_user", user_attr
+            )
+            self.assertEqual(
+                decision_service.Decision(
+                    expected_experiment,
+                    expected_variation,
+                    enums.DecisionSources.FEATURE_TEST,
+                ),
+                variation_received,
+            )
+        mock_config_logging.debug.assert_called_with('Assigned bucket 2400 to user with bucketing ID "test_user".')
+        mock_generate_bucket_value.assert_called_with('test_user111134')
+
+    def test_get_variation_for_feature__returns_variation_for_feature_in_experiment_bucket_range_2500_5000(
+        self,
+    ):
+        """ Test that if a user is in the non-mutex group and the user bucket value should be equal to 2500
+        or less than 5000."""
 
-    def test_get_experiment_in_group(self):
-        """ Test that get_experiment_in_group returns the bucketed experiment for the user. """
+        feature = self.project_config.get_feature_from_key("test_feature_in_multiple_experiments")
+        expected_experiment = self.project_config.get_experiment_from_key("test_experiment4")
+        expected_variation = self.project_config.get_variation_from_id(
+            "test_experiment4", "222240"
+        )
+        user_attr = {"experiment_attr": "group_experiment"}
 
-        group = self.project_config.get_group("19228")
-        experiment = self.project_config.get_experiment_from_id("32222")
         with mock.patch(
-            "optimizely.bucketer.Bucketer.find_bucket", return_value="32222"
-        ), self.mock_decision_logger as mock_decision_service_logging:
-            variation_received, _ = self.decision_service.get_experiment_in_group(
-                self.project_config, group, "test_user"
+            'optimizely.bucketer.Bucketer._generate_bucket_value', return_value=4000) as mock_generate_bucket_value,\
+                mock.patch.object(self.project_config, 'logger') as mock_config_logging:
+
+            variation_received, _ = self.decision_service.get_variation_for_feature(
+                self.project_config, feature, "test_user", user_attr
             )
             self.assertEqual(
-                experiment,
+                decision_service.Decision(
+                    expected_experiment,
+                    expected_variation,
+                    enums.DecisionSources.FEATURE_TEST,
+                ),
                 variation_received,
             )
+        mock_config_logging.debug.assert_called_with('Assigned bucket 4000 to user with bucketing ID "test_user".')
+        mock_generate_bucket_value.assert_called_with('test_user111135')
 
-        mock_decision_service_logging.info.assert_called_once_with(
-            'User with bucketing ID "test_user" is in experiment group_exp_1 of group 19228.'
+    def test_get_variation_for_feature__returns_variation_for_feature_in_experiment_bucket_range_5000_7500(
+        self,
+    ):
+        """ Test that if a user is in the non-mutex group and the user bucket value should be equal to 5000
+        or less than 7500."""
+
+        feature = self.project_config.get_feature_from_key("test_feature_in_multiple_experiments")
+        expected_experiment = self.project_config.get_experiment_from_key("test_experiment5")
+        expected_variation = self.project_config.get_variation_from_id(
+            "test_experiment5", "222241"
         )
+        user_attr = {"experiment_attr": "group_experiment"}
+
+        with mock.patch(
+            'optimizely.bucketer.Bucketer._generate_bucket_value', return_value=6500) as mock_generate_bucket_value,\
+                mock.patch.object(self.project_config, 'logger') as mock_config_logging:
+
+            variation_received, _ = self.decision_service.get_variation_for_feature(
+                self.project_config, feature, "test_user", user_attr
+            )
+            self.assertEqual(
+                decision_service.Decision(
+                    expected_experiment,
+                    expected_variation,
+                    enums.DecisionSources.FEATURE_TEST,
+                ),
+                variation_received,
+            )
+        mock_config_logging.debug.assert_called_with('Assigned bucket 6500 to user with bucketing ID "test_user".')
+        mock_generate_bucket_value.assert_called_with('test_user111136')
 
-    def test_get_experiment_in_group__returns_none_if_user_not_in_group(self):
-        """ Test that get_experiment_in_group returns None if the user is not bucketed into the group. """
+    def test_get_variation_for_feature__returns_variation_for_rollout_in_experiment_bucket_greater_than_7500(
+            self,
+    ):
+        """ Test that if a user is in the non-mutex group and the user bucket value should be greater than  7500."""
 
-        group = self.project_config.get_group("19228")
+        feature = self.project_config.get_feature_from_key("test_feature_in_multiple_experiments")
+        user_attr = {"experiment_attr": "group_experiment"}
         with mock.patch(
-            "optimizely.bucketer.Bucketer.find_bucket", return_value=None
-        ), self.mock_decision_logger as mock_decision_service_logging:
-            variation_received, _ = self.decision_service.get_experiment_in_group(
-                self.project_config, group, "test_user"
+            'optimizely.bucketer.Bucketer._generate_bucket_value', return_value=8000) as mock_generate_bucket_value, \
+                mock.patch.object(self.project_config, 'logger') as mock_config_logging:
+            variation_received, _ = self.decision_service.get_variation_for_feature(
+                self.project_config, feature, "test_user", user_attr
             )
-            self.assertIsNone(
-                variation_received
+            self.assertEqual(
+                decision_service.Decision(
+                    None,
+                    None,
+                    enums.DecisionSources.ROLLOUT,
+                ),
+                variation_received,
             )
 
-        mock_decision_service_logging.info.assert_called_once_with(
-            'User with bucketing ID "test_user" is not in any experiments of group 19228.'
+        mock_generate_bucket_value.assert_called_with('test_user211147')
+        mock_config_logging.debug.assert_called_with('Assigned bucket 8000 to user with bucketing ID "test_user".')
+
+    def test_get_variation_for_feature__returns_variation_for_rollout_in_mutex_group_audience_mismatch(
+            self,
+    ):
+        """ Test that if a user is in the mutex group and the user bucket value should be less than 2500 and
+        missing target by audience."""
+
+        feature = self.project_config.get_feature_from_key("test_feature_in_exclusion_group")
+        expected_experiment = self.project_config.get_experiment_from_id("211147")
+        expected_variation = self.project_config.get_variation_from_id(
+            "211147", "211149"
         )
+        user_attr = {"experiment_attr": "group_experiment_invalid"}
+        with mock.patch(
+            'optimizely.bucketer.Bucketer._generate_bucket_value', return_value=2400) as mock_generate_bucket_value, \
+                mock.patch.object(self.project_config, 'logger') as mock_config_logging:
+            variation_received, _ = self.decision_service.get_variation_for_feature(
+                self.project_config, feature, "test_user", user_attr
+            )
+
+            self.assertEqual(
+                decision_service.Decision(
+                    expected_experiment,
+                    expected_variation,
+                    enums.DecisionSources.ROLLOUT,
+                ),
+                variation_received,
+            )
+
+        mock_config_logging.debug.assert_called_with('Assigned bucket 2400 to user with bucketing ID "test_user".')
+        mock_generate_bucket_value.assert_called_with('test_user211147')
+
+    def test_get_variation_for_feature_returns_rollout_in_experiment_bucket_range_2500_5000_audience_mismatch(
+            self,
+    ):
+        """ Test that if a user is in the non-mutex group and the user bucket value should be equal to 2500
+        or less than 5000 missing target by audience."""
+
+        feature = self.project_config.get_feature_from_key("test_feature_in_multiple_experiments")
+        expected_experiment = self.project_config.get_experiment_from_id("211147")
+        expected_variation = self.project_config.get_variation_from_id(
+            "211147", "211149"
+        )
+        user_attr = {"experiment_attr": "group_experiment_invalid"}
+
+        with mock.patch(
+            'optimizely.bucketer.Bucketer._generate_bucket_value', return_value=4000) as mock_generate_bucket_value, \
+                mock.patch.object(self.project_config, 'logger') as mock_config_logging:
+            variation_received, _ = self.decision_service.get_variation_for_feature(
+                self.project_config, feature, "test_user", user_attr
+            )
+            self.assertEqual(
+                decision_service.Decision(
+                    expected_experiment,
+                    expected_variation,
+                    enums.DecisionSources.ROLLOUT,
+                ),
+                variation_received,
+            )
+        mock_config_logging.debug.assert_called_with('Assigned bucket 4000 to user with bucketing ID "test_user".')
+        mock_generate_bucket_value.assert_called_with('test_user211147')
diff --git a/tests/test_optimizely_config.py b/tests/test_optimizely_config.py
index 695cdc91..94e1fb00 100644
--- a/tests/test_optimizely_config.py
+++ b/tests/test_optimizely_config.py
@@ -196,6 +196,90 @@ def setUp(self):
                     },
                     'id': '32223',
                     'key': 'group_exp_2'
+                },
+                'group_2_exp_1': {
+                    'variations_map': {
+                        'var_1': {
+                            'variables_map': {
+
+                            },
+                            'id': '38901',
+                            'key': 'var_1',
+                            'feature_enabled': None
+                        },
+                    },
+                    'id': '42222',
+                    'key': 'group_2_exp_1'
+                },
+                'group_2_exp_2': {
+                    'variations_map': {
+                        'var_1': {
+                            'variables_map': {
+
+                            },
+                            'id': '38905',
+                            'key': 'var_1',
+                            'feature_enabled': None
+                        },
+                    },
+                    'id': '42223',
+                    'key': 'group_2_exp_2'
+                },
+                'group_2_exp_3': {
+                    'variations_map': {
+                        'var_1': {
+                            'variables_map': {
+
+                            },
+                            'id': '38906',
+                            'key': 'var_1',
+                            'feature_enabled': None
+                        },
+                    },
+                    'id': '42224',
+                    'key': 'group_2_exp_3'
+                },
+                'test_experiment3': {
+                    'variations_map': {
+                        'control': {
+                            'variables_map': {
+
+                            },
+                            'id': '222239',
+                            'key': 'control',
+                            'feature_enabled': None
+                        },
+                    },
+                    'id': '111134',
+                    'key': 'test_experiment3'
+                },
+                'test_experiment4': {
+                    'variations_map': {
+                        'control': {
+                            'variables_map': {
+
+                            },
+                            'id': '222240',
+                            'key': 'control',
+                            'feature_enabled': None
+                        },
+                    },
+                    'id': '111135',
+                    'key': 'test_experiment4'
+                },
+                'test_experiment5': {
+                    'variations_map': {
+                        'control': {
+                            'variables_map': {
+
+                            },
+                            'id': '222241',
+                            'key': 'control',
+                            'feature_enabled': None
+                        },
+                    },
+                    'id': '111136',
+                    'key': 'test_experiment5'
                 }
             },
             'features_map': {
@@ -453,6 +537,108 @@ def setUp(self):
                     },
                     'id': '91114',
                     'key': 'test_feature_in_experiment_and_rollout'
+                },
+                'test_feature_in_exclusion_group': {
+                    'variables_map': {
+
+                    },
+                    'experiments_map': {
+                        'group_2_exp_1': {
+                            'variations_map': {
+                                'var_1': {
+                                    'variables_map': {
+
+                                    },
+                                    'id': '38901',
+                                    'key': 'var_1',
+                                    'feature_enabled': None
+                                },
+                            },
+                            'id': '42222',
+                            'key': 'group_2_exp_1'
+                        },
+                        'group_2_exp_2': {
+                            'variations_map': {
+                                'var_1': {
+                                    'variables_map': {
+
+                                    },
+                                    'id': '38905',
+                                    'key': 'var_1',
+                                    'feature_enabled': None
+                                },
+                            },
+                            'id': '42223',
+                            'key': 'group_2_exp_2'
+                        },
+                        'group_2_exp_3': {
+                            'variations_map': {
+                                'var_1': {
+                                    'variables_map': {
+
+                                    },
+                                    'id': '38906',
+                                    'key': 'var_1',
+                                    'feature_enabled': None
+                                },
+                            },
+                            'id': '42224',
+                            'key': 'group_2_exp_3'
+                        }
+                    },
+                    'id': '91115',
+                    'key': 'test_feature_in_exclusion_group'
+                },
+                'test_feature_in_multiple_experiments': {
+                    'variables_map': {
+
+                    },
+                    'experiments_map': {
+                        'test_experiment3': {
+                            'variations_map': {
+                                'control': {
+                                    'variables_map': {
+
+                                    },
+                                    'id': '222239',
+                                    'key': 'control',
+                                    'feature_enabled': None
+                                },
+                            },
+                            'id': '111134',
+                            'key': 'test_experiment3'
+                        },
+                        'test_experiment4': {
+                            'variations_map': {
+                                'control': {
+                                    'variables_map': {
+
+                                    },
+                                    'id': '222240',
+                                    'key': 'control',
+                                    'feature_enabled': None
+                                },
+                            },
+                            'id': '111135',
+                            'key': 'test_experiment4'
+                        },
+                        'test_experiment5': {
+                            'variations_map': {
+                                'control': {
+                                    'variables_map': {
+
+                                    },
+                                    'id': '222241',
+                                    'key': 'control',
+                                    'feature_enabled': None
+                                },
+                            },
+                            'id': '111136',
+                            'key': 'test_experiment5'
+                        }
+                    },
+                    'id': '91116',
+                    'key': 'test_feature_in_multiple_experiments'
                 }
             },
             'revision': '1',
diff --git a/tests/test_user_context.py b/tests/test_user_context.py
index abc18a87..7c979028 100644
--- a/tests/test_user_context.py
+++ b/tests/test_user_context.py
@@ -1040,7 +1040,9 @@ def test_decide_for_all(self):
                 'test_feature_in_experiment',
                 'test_feature_in_rollout',
                 'test_feature_in_group',
-                'test_feature_in_experiment_and_rollout'
+                'test_feature_in_experiment_and_rollout',
+                'test_feature_in_exclusion_group',
+                'test_feature_in_multiple_experiments'
             ],
             options
         )