diff --git a/config/global.ini.php b/config/global.ini.php
index 04cfda60c05ae5c25c7a16cabf7ed43d05ce1c65..af34d5f93f15e2e6c523e99f14370d66611543bf 100644
--- a/config/global.ini.php
+++ b/config/global.ini.php
@@ -199,6 +199,9 @@ campaign_keyword_var_name	= piwik_kwd
 ; maximum length of a Page Title or a Page URL recorded in the log_action.name table
 page_maximum_length = 1024;
 
+; number of octets in IP address to mask, in order to anonymize a visitor's IP address; if the AnonymizeIP plugin is deactivated, this value is ignored; for IPv4 addresses, valid values are 0..4
+ip_address_mask_length = 1
+
 [log]
 ;possible values for log: screen, database, file
 ; normal messages
diff --git a/lang/en.php b/lang/en.php
index fb0167d6bf4f82009c5f8c3cb6909b0cd2b5fac2..7f441696a0c0e394c905e51596715b3590f6b34f 100644
--- a/lang/en.php
+++ b/lang/en.php
@@ -128,6 +128,7 @@ $translations = array(
 	'Actions_ColumnPageURL' => 'Page URL',
 	'Actions_ColumnClickedURL' => 'Clicked URL',
 	'Actions_ColumnDownloadURL' => 'Download URL',
+	'AnonymizeIP_PluginDescription' => 'Anonymize visitor IP addresses to comply with your local privacy laws/guidelines.',
 	'API_PluginDescription' => 'All the data in Piwik is available through simple APIs. This plugin is the web service entry point, that you can call to get your Web Analytics data in xml, json, php, csv, etc.',
 	'API_QuickDocumentation' => '<h2>API quick documentation</h2><p>If you don\'t have data for today you can first <a href=\'misc/generateVisits.php\' target=_blank>generate some data</a> using the Visits Generator script.</p><p>You can try the different formats available for every method. It is very easy to extract any data you want from Piwik!</p><p><b>For more information have a look at the <a href=\'http://dev.piwik.org/trac/wiki/API\'>official API Documentation</a> or the <a href=\'http://dev.piwik.org/trac/wiki/API/Reference\'>API Reference</a>.</b></P><h2>User authentication</h2><p>If you want to <b>request the data in your scripts, in a crontab, etc. </b> you need to add the parameter <code><u>&amp;token_auth=%s</u></code> to the API calls URLs that require authentication.</p><p>This token_auth is as secret as your login and password, <b>do not share it!</p>',
 	'API_LoadedAPIs' => 'Loaded successfully %s APIs',
diff --git a/plugins/AnonymizeIP/AnonymizeIP.php b/plugins/AnonymizeIP/AnonymizeIP.php
new file mode 100644
index 0000000000000000000000000000000000000000..67082cb7acfc16a469d413ae87c71758c03e1bac
--- /dev/null
+++ b/plugins/AnonymizeIP/AnonymizeIP.php
@@ -0,0 +1,80 @@
+<?php
+/**
+ * Piwik - Open source web analytics
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html Gpl v3 or later
+ * @version $Id$
+ *
+ * @category Piwik_Plugins
+ * @package Piwik_AnonymizeIP
+ */
+
+/**
+ * Anonymize visitor IP addresses to comply with the privacy laws/guidelines in countries, such as Germany.
+ *
+ * @package Piwik_AnonymizeIP
+ */
+class Piwik_AnonymizeIP extends Piwik_Plugin
+{
+	/**
+	 * Get plugin information
+	 */
+	public function getInformation()
+	{
+		return array(
+			'name' => 'AnonymizeIP',
+			'description' => Piwik_Translate('AnonymizeIP_PluginDescription'),
+			'author' => 'Piwik',
+			'author_homepage' => 'http://piwik.org/',
+			'version' => Piwik_Version::VERSION,
+			'TrackerPlugin' => true,
+		);
+	}
+
+	/**
+	 * Get list of hooks to register
+	 */
+	public function getListHooksRegistered()
+	{
+		return array(
+			'Tracker.saveVisitorInformation' => 'anonymizeVisitorIpAddress',
+		);
+	}
+
+	/**
+	 * Internal function to mask portions of the visitor IP address
+	 *
+	 * @param $ip Unsigned long representation of IP address
+	 * @param $maskLength Number of octets to reset
+	 */
+	static public function applyIPMask($ip, $maskLength)
+	{
+		$maskedIP = pack('V', (float)$ip);
+
+		switch($maskLength) {
+			case 4:
+				$maskedIP[3] = "\0";
+			case 3:
+				$maskedIP[2] = "\0";
+			case 2:
+				$maskedIP[1] = "\0";
+			case 1:
+				$maskedIP[0] = "\0";
+			case 0:
+			default:
+		}
+
+		$res = unpack('V', $maskedIP);
+		return sprintf("%u", $res[1]);
+	}
+
+	/**
+	 * Hook on Tracker.saveVisitorInformation to anonymize visitor IP addresses
+	 */
+	function anonymizeVisitorIpAddress($notification)
+	{
+		$visitorInfo =& $notification->getNotificationObject();
+		$visitorInfo['location_ip'] = self::applyIPMask($visitorInfo['location_ip'], Piwik_Tracker_Config::getInstance()->Tracker['ip_address_mask_length']);
+	}
+}
diff --git a/plugins/AnonymizeIP/tests/AnonymizeIP.test.php b/plugins/AnonymizeIP/tests/AnonymizeIP.test.php
new file mode 100644
index 0000000000000000000000000000000000000000..7afd3e68bc845f751a75fd2a69baad1f6a034881
--- /dev/null
+++ b/plugins/AnonymizeIP/tests/AnonymizeIP.test.php
@@ -0,0 +1,46 @@
+<?php
+if(!defined("PIWIK_PATH_TEST_TO_ROOT")) {
+	define('PIWIK_PATH_TEST_TO_ROOT', getcwd().'/../../..');
+}
+if(!defined('PIWIK_CONFIG_TEST_INCLUDED'))
+{
+	require_once PIWIK_PATH_TEST_TO_ROOT . "/tests/config_test.php";
+}
+
+if(!class_exists('Piwik_AnonymizeIP', false))
+{
+	require_once dirname(__FILE__) . '/../AnonymizeIP.php';
+}
+
+class Test_Piwik_AnonymizeIP extends UnitTestCase
+{
+	// IP addresses and expected results
+	protected $ipAddresses = array(
+		// long => array( expected0, expected1, expected2, expected3, expected4 ),
+		'0'   => array( 0, 0, 0, 0, 0 ),													// 00 00 00 00
+		'1'   => array( 1, 0, 0, 0, 0 ),													// 00 00 00 01
+		'255' => array( 255, 0, 0, 0, 0 ),													// 00 00 00 FF
+		'256' => array( 256, 256, 0, 0, 0 ),												// 00 00 01 00
+		'257' => array( 257, 256, 0, 0, 0 ),												// 00 00 01 01
+		'65535' => array( 65535, 65280, 0, 0, 0),											// 00 00 FF FF
+		'65536' => array( 65536, 65536, 65536, 0, 0),										// 00 01 00 00
+		'65793' => array( 65793, 65792, 65536, 0, 0),										// 00 01 01 01
+		'16777215' => array( 16777215, 16776960, 16711680, 0, 0),							// 00 FF FF FF
+		'16777216' => array( 16777216, 16777216, 16777216, 16777216, 0),					// 01 00 00 00
+		'2147483647' => array( 2147483647, 2147483392, 2147418112, 2130706432, 0),			// 7F FF FF FF
+		'2147483648' => array( '2147483648', '2147483648', '2147483648', '2147483648', 0),	// 80 00 00 00
+		'4294967295' => array( '4294967295', '4294967040', '4294901760', '4278190080', 0),	// FF FF FF FF
+	);
+
+	public function test_applyIPMask()
+	{
+		foreach($this->ipAddresses as $ip => $expected)
+		{
+			// each IP is tested with 0 to 4 octets masked
+			for($maskLength = 0; $maskLength <= 4; $maskLength++)
+			{
+				$this->assertTrue( Piwik_AnonymizeIP::applyIPMask($ip, $maskLength) == $expected[$maskLength] );
+			}
+		}
+	}
+}