diff --git a/config/global.ini.php b/config/global.ini.php
index 2bab7b130d71ad47004c0161932d85f37c0a1a7e..b4fde4c35828da0ddf10c8302cc13086b6dab21f 100644
--- a/config/global.ini.php
+++ b/config/global.ini.php
@@ -586,6 +586,16 @@ campaign_var_name = "pk_cpn,pk_campaign,piwik_campaign,utm_campaign,utm_source,u
 ; Includes by default the GA style campaign keyword parameter utm_term
 campaign_keyword_var_name = "pk_kwd,pk_keyword,piwik_kwd,utm_term"
 
+; if set to 1, actions that contain different campaign information from the last action in the current visit will
+; be treated as the start of a new visit. This will include situations when campaign information was absent before,
+; but is present now (or vice versa).
+tracker_create_new_visit_when_campaign_changes = 1
+
+; if set to 1, actions that contain different website referrer information from the last action in the current visit
+; will be treatedas the start of a new visit. This will include situations when website referrer information was
+; absent before, but is present now (or vice versa).
+tracker_create_new_visit_when_website_referrer_changes = 0
+
 ; maximum length of a Page Title or a Page URL recorded in the log_action.name table
 page_maximum_length = 1024;
 
diff --git a/core/Columns/Dimension.php b/core/Columns/Dimension.php
index e760a090832de1e210782194d2a6dcd6148f085c..0da3bcf8b3db4de3c07b4aedfec141d203ab14f2 100644
--- a/core/Columns/Dimension.php
+++ b/core/Columns/Dimension.php
@@ -15,6 +15,9 @@ use Piwik\Plugin\Dimension\ActionDimension;
 use Piwik\Plugin\Dimension\ConversionDimension;
 use Piwik\Plugin\Dimension\VisitDimension;
 use Piwik\Plugin\Segment;
+use Piwik\Tracker\Action;
+use Piwik\Tracker\Request;
+use Piwik\Tracker\Visitor;
 use Piwik\Translate;
 
 /**
@@ -166,6 +169,25 @@ abstract class Dimension
         return $pluginName . '.' . $dimensionName;
     }
 
+    /**
+     * This hook is executed by the tracker when determining if an action is the start of a new visit
+     * or part of an existing one. Derived classes can use it to force new visits based on dimension
+     * data.
+     *
+     * For example, the Campaign dimension in the Referrers plugin will force a new visit if the
+     * campaign information for the current action is different from the last.
+     *
+     * @param Request $request The current tracker request information.
+     * @param Visitor $visitor The information for the currently recognized visitor.
+     * @param Action|null $action The current action information (if any).
+     * @return bool Return true to force a visit, false if otherwise.
+     * @api
+     */
+    public function shouldForceNewVisit(Request $request, Visitor $visitor, Action $action = null)
+    {
+        return false;
+    }
+
     /**
      * Gets an instance of all available visit, action and conversion dimension.
      * @return Dimension[]
diff --git a/core/Tracker/Visit.php b/core/Tracker/Visit.php
index 4065ebe15cba87e849969045a36ee68e3f000e3f..869434d4cd447828016e0a01c4cdcaa41850172c 100644
--- a/core/Tracker/Visit.php
+++ b/core/Tracker/Visit.php
@@ -152,11 +152,7 @@ class Visit implements VisitInterface
 
         $this->visitorInfo = $visitor->getVisitorInfo();
 
-        $isLastActionInTheSameVisit = $this->isLastActionInTheSameVisit($visitor);
-
-        if (!$isLastActionInTheSameVisit) {
-            Common::printDebug("Visitor detected, but last action was more than 30 minutes ago...");
-        }
+        $isNewVisit = $this->isVisitNew($visitor, $action);
 
         // Known visit when:
         // ( - the visitor has the Piwik cookie with the idcookie ID used by Piwik to match the visitor
@@ -165,9 +161,7 @@ class Visit implements VisitInterface
         // )
         // AND
         // - the last page view for this visitor was less than 30 minutes ago @see isLastActionInTheSameVisit()
-        if ($visitor->isVisitorKnown()
-            && $isLastActionInTheSameVisit
-        ) {
+        if (!$isNewVisit) {
             $idReferrerActionUrl  = $this->visitorInfo['visit_exit_idaction_url'];
             $idReferrerActionName = $this->visitorInfo['visit_exit_idaction_name'];
 
@@ -203,9 +197,7 @@ class Visit implements VisitInterface
         // - the visitor has the Piwik cookie but the last action was performed more than 30 min ago @see isLastActionInTheSameVisit()
         // - the visitor doesn't have the Piwik cookie, and couldn't be matched in @see recognizeTheVisitor()
         // - the visitor does have the Piwik cookie but the idcookie and idvisit found in the cookie didn't match to any existing visit in the DB
-        if (!$visitor->isVisitorKnown()
-            || !$isLastActionInTheSameVisit
-        ) {
+        if ($isNewVisit) {
             $this->handleNewVisit($visitor, $action, $visitIsConverted);
             if (!is_null($action)) {
                 $action->record($visitor, 0, 0);
@@ -550,6 +542,23 @@ class Visit implements VisitInterface
         return $valuesToUpdate;
     }
 
+    private function triggerPredicateHookOnDimensions($dimensions, $hook, Visitor $visitor, Action $action = null, $returnFirstTrue = true)
+    {
+        $result = $returnFirstTrue ? false : array();
+        foreach ($dimensions as $dimension) {
+            $value = $dimension->$hook($this->request, $visitor, $action);
+
+            if ($returnFirstTrue) {
+                if ($value) {
+                    return true;
+                }
+            } else {
+                $result[] = $value;
+            }
+        }
+        return $result;
+    }
+
     protected function getAllVisitDimensions()
     {
         $dimensions = VisitDimension::getAllDimensions();
@@ -598,4 +607,39 @@ class Visit implements VisitInterface
     {
         return $this->getModel()->createVisit($visit);
     }
+
+    /**
+     * Determines if the tracker if the current action should be treated as the start of a new visit or
+     * an action in an existing visit.
+     *
+     * @param Visitor $visitor The current visit/visitor information.
+     * @param Action|null $action The current action being tracked.
+     * @return bool
+     */
+    private function isVisitNew(Visitor $visitor, Action $action = null)
+    {
+        $isLastActionInTheSameVisit = $this->isLastActionInTheSameVisit($visitor);
+
+        if (!$isLastActionInTheSameVisit) {
+            Common::printDebug("Visitor detected, but last action was more than 30 minutes ago...");
+
+            return true;
+        }
+
+        $shouldForceNewVisit = $this->triggerPredicateHookOnDimensions($this->getAllVisitDimensions(), 'shouldForceNewVisit', $visitor, $action);
+        if ($shouldForceNewVisit) {
+            return true;
+        }
+
+        // if we should create a new visit when the referrer changes, check if referrer changed
+        if ($this->createNewVisitWhenWebsiteReferrerChanges
+            && $visitor->isReferrerInformationDifferent()
+        ) {
+            Common::printDebug("Existing visit detected, but creating new visit because referrer information is different than last action");
+
+            return true;
+        }
+
+        return !$visitor->isVisitorKnown();
+    }
 }
diff --git a/plugins/Referrers/Columns/Base.php b/plugins/Referrers/Columns/Base.php
index a69fcc54bfe3639fd3d4b6104cb476738d0ca2e6..a721dc942192383aa4244431f4dcecf510563672 100644
--- a/plugins/Referrers/Columns/Base.php
+++ b/plugins/Referrers/Columns/Base.php
@@ -127,6 +127,14 @@ abstract class Base extends VisitDimension
         return $referrerInformation;
     }
 
+    protected function getReferrerInformationFromRequest(Request $request)
+    {
+        $referrerUrl = $request->getParam('urlref');
+        $currentUrl  = $request->getParam('url');
+
+        return $this->getReferrerInformation($referrerUrl, $currentUrl, $request->getIdSite());
+    }
+
     /**
      * Search engine detection
      * @return bool
@@ -399,4 +407,24 @@ abstract class Base extends VisitDimension
         }
     }
 
-}
+    protected function hasReferrerInformationChanged(Visitor $visitor, $information)
+    {
+        foreach (array('referer_keyword', 'referer_name', 'referer_type') as $infoName) {
+            if ($this->hasReferrerColumnChanged($visitor, $information, $infoName)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    protected function hasReferrerColumnChanged(Visitor $visitor, $information, $infoName)
+    {
+        return Common::mb_strtolower($visitor->getVisitorColumn($infoName)) != $information[$infoName];
+    }
+
+    protected function doesLastOrCurrentActionHaveSameReferrer(Visitor $visitor, $currentInformation, $referrerType)
+    {
+        return $visitor->getVisitorColumn('referer_type') == $referrerType
+        || $currentInformation['referer_type'] == $referrerType;
+    }
+}
\ No newline at end of file
diff --git a/plugins/Referrers/Columns/Campaign.php b/plugins/Referrers/Columns/Campaign.php
index 4413cd702f65a9eb936d872f41c9790031cc227e..53f86e97ebaadda0b2aa77f85b98933fc0617490 100644
--- a/plugins/Referrers/Columns/Campaign.php
+++ b/plugins/Referrers/Columns/Campaign.php
@@ -8,13 +8,58 @@
  */
 namespace Piwik\Plugins\Referrers\Columns;
 
-use Piwik\Columns\Dimension;
+use Piwik\Common;
 use Piwik\Piwik;
+use Piwik\Tracker\Action;
+use Piwik\Tracker\Request;
+use Piwik\Tracker\TrackerConfig;
+use Piwik\Tracker\Visitor;
 
-class Campaign extends Dimension
+class Campaign extends Base
 {
+    /**
+     * Obtained from the `[Tracker] tracker_create_new_visit_when_campaign_changes` INI config option.
+     * If true, will create new visits when campaign name changes.
+     *
+     * @var bool
+     */
+    protected $createNewVisitWhenCampaignChanges;
+
+    public function __construct()
+    {
+        $this->createNewVisitWhenCampaignChanges = TrackerConfig::getConfigValue('tracker_create_new_visit_when_campaign_changes') == 1;
+    }
+
     public function getName()
     {
         return Piwik::translate('Referrers_ColumnCampaign');
     }
-}
+
+    /**
+     * If we should create a new visit when the campaign changes, check if the campaign info changed and if so
+     * force the tracker to create a new visit.
+     *
+     * @param Request $request
+     * @param Visitor $visitor
+     * @param Action|null $action
+     * @return bool
+     */
+    public function shouldForceNewVisit(Request $request, Visitor $visitor, Action $action = null)
+    {
+        if (!$this->createNewVisitWhenCampaignChanges) {
+            return false;
+        }
+
+        $information = $this->getReferrerInformationFromRequest($request);
+
+        if ($this->doesLastOrCurrentActionHaveSameReferrer($visitor, $information, Common::REFERRER_TYPE_CAMPAIGN)
+            && $this->hasReferrerInformationChanged($visitor, $information)
+        ) {
+            Common::printDebug("Existing visit detected, but creating new visit because campaign information is different than last action.");
+
+            return true;
+        }
+
+        return false;
+    }
+}
\ No newline at end of file
diff --git a/plugins/Referrers/Columns/Keyword.php b/plugins/Referrers/Columns/Keyword.php
index a5025b63c21cc7b7696285ea7d9c3273b3091440..78605c9d94a4f742119e05be62870d9ee916165a 100644
--- a/plugins/Referrers/Columns/Keyword.php
+++ b/plugins/Referrers/Columns/Keyword.php
@@ -41,10 +41,7 @@ class Keyword extends Base
      */
     public function onNewVisit(Request $request, Visitor $visitor, $action)
     {
-        $referrerUrl = $request->getParam('urlref');
-        $currentUrl  = $request->getParam('url');
-
-        $information = $this->getReferrerInformation($referrerUrl, $currentUrl, $request->getIdSite());
+        $information = $this->getReferrerInformationFromRequest($request);
 
         if (!empty($information['referer_keyword'])) {
             return substr($information['referer_keyword'], 0, 255);
diff --git a/plugins/Referrers/Columns/ReferrerName.php b/plugins/Referrers/Columns/ReferrerName.php
index fbd55219dccdc55bd696f578f161fb7fe8c4f308..7bdb0732a67d855ecefb9ccba21e753c564922a5 100644
--- a/plugins/Referrers/Columns/ReferrerName.php
+++ b/plugins/Referrers/Columns/ReferrerName.php
@@ -35,10 +35,7 @@ class ReferrerName extends Base
      */
     public function onNewVisit(Request $request, Visitor $visitor, $action)
     {
-        $referrerUrl = $request->getParam('urlref');
-        $currentUrl  = $request->getParam('url');
-
-        $information = $this->getReferrerInformation($referrerUrl, $currentUrl, $request->getIdSite());
+        $information = $this->getReferrerInformationFromRequest($request);
 
         if (!empty($information['referer_name'])) {
 
diff --git a/plugins/Referrers/Columns/ReferrerType.php b/plugins/Referrers/Columns/ReferrerType.php
index f4e688f60e05d5959bfb62f5c940214d32b68b42..5303a1c360f13ad194676b5df9b247e5bcc38387 100644
--- a/plugins/Referrers/Columns/ReferrerType.php
+++ b/plugins/Referrers/Columns/ReferrerType.php
@@ -42,10 +42,7 @@ class ReferrerType extends Base
      */
     public function onNewVisit(Request $request, Visitor $visitor, $action)
     {
-        $referrerUrl = $request->getParam('urlref');
-        $currentUrl  = $request->getParam('url');
-
-        $information = $this->getReferrerInformation($referrerUrl, $currentUrl, $request->getIdSite());
+        $information = $this->getReferrerInformationFromRequest($request);
 
         return $information['referer_type'];
     }
diff --git a/plugins/Referrers/Columns/ReferrerUrl.php b/plugins/Referrers/Columns/ReferrerUrl.php
index 0404a132472c9fca1e8aaadca95b2e58dd43e260..21c5cd5bdcc281ab3fb758cfaa8f7e423eaf7039 100644
--- a/plugins/Referrers/Columns/ReferrerUrl.php
+++ b/plugins/Referrers/Columns/ReferrerUrl.php
@@ -35,10 +35,7 @@ class ReferrerUrl extends Base
      */
     public function onNewVisit(Request $request, Visitor $visitor, $action)
     {
-        $referrerUrl = $request->getParam('urlref');
-        $currentUrl  = $request->getParam('url');
-
-        $information = $this->getReferrerInformation($referrerUrl, $currentUrl, $request->getIdSite());
+        $information = $this->getReferrerInformationFromRequest($request);
 
         return $information['referer_url'];
     }
diff --git a/plugins/Referrers/Columns/Website.php b/plugins/Referrers/Columns/Website.php
index 53b143d6933f1ae33956ef2d603347aedfb7bdc3..7d4903c902af34e77b033aaf360f351cf00be6b9 100644
--- a/plugins/Referrers/Columns/Website.php
+++ b/plugins/Referrers/Columns/Website.php
@@ -8,13 +8,50 @@
  */
 namespace Piwik\Plugins\Referrers\Columns;
 
-use Piwik\Columns\Dimension;
+use Piwik\Common;
 use Piwik\Piwik;
+use Piwik\Tracker\Action;
+use Piwik\Tracker\Request;
+use Piwik\Tracker\TrackerConfig;
+use Piwik\Tracker\Visitor;
 
-class Website extends Dimension
+class Website extends Base
 {
+    /**
+     * Set using the `[Tracker] tracker_create_new_visit_when_website_referrer_changes` INI config option.
+     * If true, will force new visits if the referrer website changes.
+     *
+     * @var bool
+     */
+    protected $createNewVisitWhenWebsiteReferrerChanges;
+
+    public function __construct()
+    {
+        $this->createNewVisitWhenWebsiteReferrerChanges = TrackerConfig::getConfigValue('tracker_create_new_visit_when_website_referrer_changes') == 1;
+    }
+
     public function getName()
     {
         return Piwik::translate('General_Website');
     }
+
+    public function shouldForceNewVisit(Request $request, Visitor $visitor, Action $action = null)
+    {
+        if (!$this->createNewVisitWhenWebsiteReferrerChanges) {
+            return false;
+        }
+
+        $information = $this->getReferrerInformationFromRequest($request);
+
+        if ($this->doesLastOrCurrentActionHaveSameReferrer($visitor, $information, Common::REFERRER_TYPE_WEBSITE)
+            && $this->hasReferrerInformationChanged($visitor, $information)
+        ) {
+            Common::printDebug("Existing visit detected, but creating new visit because website referrer information is different than last action.");
+
+            return true;
+        }
+
+        return false;
+
+    }
 }
\ No newline at end of file