diff --git a/modules/search/search.test b/modules/search/search.test
index 26c663e..0ea1018 100644
--- a/modules/search/search.test
+++ b/modules/search/search.test
@@ -441,8 +441,14 @@ class SearchRankingTestCase extends DrupalWebTestCase {
     variable_set('statistics_count_content_views', 1);
 
     // Then View one of the nodes a bunch of times.
+    // Manually calling statistics.php, simulating ajax behavior.
+    $nid = $nodes['views'][1]->nid;
+    $post = http_build_query(array('nid' => $nid));
+    $headers = array('Content-Type' => 'application/x-www-form-urlencoded');
+    global $base_url;
+    $stats_path = $base_url . '/' . drupal_get_path('module', 'statistics'). '/statistics.php';
     for ($i = 0; $i < 5; $i ++) {
-      $this->drupalGet('node/' . $nodes['views'][1]->nid);
+      drupal_http_request($stats_path, array('method' => 'POST', 'data' => $post, 'headers' => $headers, 'timeout' => 10000));
     }
 
     // Test each of the possible rankings.
@@ -464,7 +470,7 @@ class SearchRankingTestCase extends DrupalWebTestCase {
   function testHTMLRankings() {
     // Login with sufficient privileges.
     $this->drupalLogin($this->drupalCreateUser(array('create page content')));
-    
+
     // Test HTML tags with different weights.
     $sorted_tags = array('h1', 'h2', 'h3', 'h4', 'a', 'h5', 'h6', 'notag');
     $shuffled_tags = $sorted_tags;
@@ -496,7 +502,7 @@ class SearchRankingTestCase extends DrupalWebTestCase {
 
     // Refresh variables after the treatment.
     $this->refreshVariables();
-    
+
     // Disable all other rankings.
     $node_ranks = array('sticky', 'promote', 'recent', 'comments', 'views');
     foreach ($node_ranks as $node_rank) {
@@ -534,7 +540,7 @@ class SearchRankingTestCase extends DrupalWebTestCase {
 
       // Assert the results.
       $this->assertEqual($set[0]['node']->nid, $node->nid, 'Search tag ranking for "&lt;' . $tag . '&gt;" order.');
-      
+
       // Delete node so it doesn't show up in subsequent search results.
       node_delete($node->nid);
     }
@@ -875,7 +881,7 @@ class SearchCommentTestCase extends DrupalWebTestCase {
     $this->setRolePermissions(DRUPAL_AUTHENTICATED_RID, TRUE, TRUE);
     $this->setRolePermissions($this->admin_role, TRUE, FALSE);
     $this->checkCommentAccess('Admin user has access comments permission and no search permission, but comments should be indexed because admin user inherits authenticated user\'s permission to search', TRUE);
-    
+
   }
 
   /**
diff --git a/modules/statistics/statistics.js b/modules/statistics/statistics.js
new file mode 100644
index 0000000..c7ff2ea
--- /dev/null
+++ b/modules/statistics/statistics.js
@@ -0,0 +1,12 @@
+(function ($) {
+  $(document).ready(function() {
+    var nid = Drupal.settings.statistics.nid;
+    var basePath = Drupal.settings.basePath
+    $.ajax({
+      type: "POST",
+      cache: false,
+      url: basePath+"modules/statistics/statistics.php",
+      data: "nid="+nid
+    });
+  });
+})(jQuery);
diff --git a/modules/statistics/statistics.module b/modules/statistics/statistics.module
index 89cda6d..a1135b5 100644
--- a/modules/statistics/statistics.module
+++ b/modules/statistics/statistics.module
@@ -57,22 +57,6 @@ function statistics_exit() {
   // in which case we need to bootstrap to the session phase anyway.
   drupal_bootstrap(DRUPAL_BOOTSTRAP_VARIABLES);
 
-  if (variable_get('statistics_count_content_views', 0)) {
-    // We are counting content views.
-    if (arg(0) == 'node' && is_numeric(arg(1)) && arg(2) == NULL) {
-      // A node has been viewed, so update the node's counters.
-      db_merge('node_counter')
-        ->key(array('nid' => arg(1)))
-        ->fields(array(
-          'daycount' => 1,
-          'totalcount' => 1,
-          'timestamp' => REQUEST_TIME,
-        ))
-        ->expression('daycount', 'daycount + 1')
-        ->expression('totalcount', 'totalcount + 1')
-        ->execute();
-    }
-  }
   if (variable_get('statistics_enable_access_log', 0)) {
     drupal_bootstrap(DRUPAL_BOOTSTRAP_SESSION);
 
@@ -115,6 +99,19 @@ function statistics_permission() {
  * Implements hook_node_view().
  */
 function statistics_node_view($node, $view_mode) {
+  if (!empty($node->nid) && $view_mode == 'full') {
+    $node->content['#attached']['js'] = array(
+      drupal_get_path('module', 'statistics') . '/statistics.js' => array(
+        'scope' => 'footer'
+      ),
+    );
+    $settings = array('nid' => $node->nid);
+    $node->content['#attached']['js'][] = array(
+      'data' => array('statistics' => $settings),
+      'type' => 'setting',
+    );
+  }
+
   if ($view_mode != 'rss') {
     if (user_access('view post access counter')) {
       $statistics = statistics_get($node->nid);
diff --git a/modules/statistics/statistics.php b/modules/statistics/statistics.php
new file mode 100644
index 0000000..d3c3b9c
--- /dev/null
+++ b/modules/statistics/statistics.php
@@ -0,0 +1,32 @@
+<?php
+
+/**
+ * @file
+ * Handles counts of node views via AJAX with minimal bootstrap.
+ */
+
+// Change the directory to the Drupal root.
+chdir('../..');
+
+/**
+* Root directory of Drupal installation.
+*/
+define('DRUPAL_ROOT', getcwd());
+
+include_once DRUPAL_ROOT . '/includes/bootstrap.inc';
+drupal_bootstrap(DRUPAL_BOOTSTRAP_VARIABLES);
+if (variable_get('statistics_count_content_views', 0)) {
+  $nid = $_POST['nid'];
+  if (is_numeric($nid)) {
+    db_merge('node_counter')
+      ->key(array('nid' => $nid))
+      ->fields(array(
+        'daycount' => 1,
+        'totalcount' => 1,
+        'timestamp' => REQUEST_TIME,
+      ))
+      ->expression('daycount', 'daycount + 1')
+      ->expression('totalcount', 'totalcount + 1')
+      ->execute();
+  }
+}
diff --git a/modules/statistics/statistics.test b/modules/statistics/statistics.test
index f12490a..c2ea5a7 100644
--- a/modules/statistics/statistics.test
+++ b/modules/statistics/statistics.test
@@ -92,6 +92,13 @@ class StatisticsLoggingTestCase extends DrupalWebTestCase {
 
     // Verify logging of an uncached page.
     $this->drupalGet($path);
+    // Manually calling statistics.php, simulating ajax behavior.
+    $nid = $this->node->nid;
+    $post = http_build_query(array('nid' => $nid));
+    $headers = array('Content-Type' => 'application/x-www-form-urlencoded');
+    global $base_url;
+    $stats_path = $base_url . '/' . drupal_get_path('module', 'statistics'). '/statistics.php';
+    drupal_http_request($stats_path, array('method' => 'POST', 'data' => $post, 'headers' => $headers, 'timeout' => 10000));
     $this->assertIdentical($this->drupalGetHeader('X-Drupal-Cache'), 'MISS', t('Testing an uncached page.'));
     $log = db_query('SELECT * FROM {accesslog}')->fetchAll(PDO::FETCH_ASSOC);
     $this->assertTrue(is_array($log) && count($log) == 1, t('Page request was logged.'));
@@ -101,6 +108,8 @@ class StatisticsLoggingTestCase extends DrupalWebTestCase {
 
     // Verify logging of a cached page.
     $this->drupalGet($path);
+    // Manually calling statistics.php, simulating ajax behavior.
+    drupal_http_request($stats_path, array('method' => 'POST', 'data' => $post, 'headers' => $headers, 'timeout' => 10000));
     $this->assertIdentical($this->drupalGetHeader('X-Drupal-Cache'), 'HIT', t('Testing a cached page.'));
     $log = db_query('SELECT * FROM {accesslog}')->fetchAll(PDO::FETCH_ASSOC);
     $this->assertTrue(is_array($log) && count($log) == 2, t('Page request was logged.'));
@@ -111,6 +120,8 @@ class StatisticsLoggingTestCase extends DrupalWebTestCase {
     // Test logging from authenticated users
     $this->drupalLogin($this->auth_user);
     $this->drupalGet($path);
+    // Manually calling statistics.php, simulating ajax behavior.
+    drupal_http_request($stats_path, array('method' => 'POST', 'data' => $post, 'headers' => $headers, 'timeout' => 10000));
     $log = db_query('SELECT * FROM {accesslog}')->fetchAll(PDO::FETCH_ASSOC);
     // Check the 6th item since login and account pages are also logged
     $this->assertTrue(is_array($log) && count($log) == 6, t('Page request was logged.'));
@@ -125,6 +136,8 @@ class StatisticsLoggingTestCase extends DrupalWebTestCase {
       'path' => $path,
     );
     $this->drupalGet($path);
+    // Manually calling statistics.php, simulating ajax behavior.
+    drupal_http_request($stats_path, array('method' => 'POST', 'data' => $post, 'headers' => $headers, 'timeout' => 10000));
     $log = db_query('SELECT * FROM {accesslog}')->fetchAll(PDO::FETCH_ASSOC);
     $this->assertTrue(is_array($log) && count($log) == 7, t('Page request was logged.'));
     $this->assertEqual(array_intersect_key($log[6], $expected), $expected);
@@ -207,6 +220,13 @@ class StatisticsReportsTestCase extends StatisticsTestCase {
     // Visit a node to have something show up in the block.
     $node = $this->drupalCreateNode(array('type' => 'page', 'uid' => $this->blocking_user->uid));
     $this->drupalGet('node/' . $node->nid);
+    // Manually calling statistics.php, simulating ajax behavior.
+    $nid = $node->nid;
+    $post = http_build_query(array('nid' => $nid));
+    $headers = array('Content-Type' => 'application/x-www-form-urlencoded');
+    global $base_url;
+    $stats_path = $base_url . '/' . drupal_get_path('module', 'statistics'). '/statistics.php';
+    drupal_http_request($stats_path, array('method' => 'POST', 'data' => $post, 'headers' => $headers, 'timeout' => 10000));
 
     // Configure and save the block.
     $block = block_load('statistics', 'popular');
@@ -322,6 +342,13 @@ class StatisticsAdminTestCase extends DrupalWebTestCase {
 
     // Hit the node.
     $this->drupalGet('node/' . $this->test_node->nid);
+    // Manually calling statistics.php, simulating ajax behavior.
+    $nid = $this->test_node->nid;
+    $post = http_build_query(array('nid' => $nid));
+    $headers = array('Content-Type' => 'application/x-www-form-urlencoded');
+    global $base_url;
+    $stats_path = $base_url . '/' . drupal_get_path('module', 'statistics'). '/statistics.php';
+    drupal_http_request($stats_path, array('method' => 'POST', 'data' => $post, 'headers' => $headers, 'timeout' => 10000));
 
     $this->drupalGet('admin/reports/pages');
     $this->assertText('node/1', t('Test node found.'));
@@ -329,9 +356,12 @@ class StatisticsAdminTestCase extends DrupalWebTestCase {
     // Hit the node again (the counter is incremented after the hit, so
     // "1 read" will actually be shown when the node is hit the second time).
     $this->drupalGet('node/' . $this->test_node->nid);
+    // Manually calling statistics.php, simulating ajax behavior.
+    drupal_http_request($stats_path, array('method' => 'POST', 'data' => $post, 'headers' => $headers, 'timeout' => 10000));
     $this->assertText('1 read', t('Node is read once.'));
 
     $this->drupalGet('node/' . $this->test_node->nid);
+    drupal_http_request($stats_path, array('method' => 'POST', 'data' => $post, 'headers' => $headers, 'timeout' => 10000));
     $this->assertText('2 reads', t('Node is read 2 times.'));
   }
 
@@ -342,6 +372,13 @@ class StatisticsAdminTestCase extends DrupalWebTestCase {
     variable_set('statistics_count_content_views', 1);
 
     $this->drupalGet('node/' . $this->test_node->nid);
+    // Manually calling statistics.php, simulating ajax behavior.
+    $nid = $this->test_node->nid;
+    $post = http_build_query(array('nid' => $nid));
+    $headers = array('Content-Type' => 'application/x-www-form-urlencoded');
+    global $base_url;
+    $stats_path = $base_url . '/' . drupal_get_path('module', 'statistics'). '/statistics.php';
+    drupal_http_request($stats_path, array('method' => 'POST', 'data' => $post, 'headers' => $headers, 'timeout' => 10000));
 
     $result = db_select('node_counter', 'n')
       ->fields('n', array('nid'))
@@ -397,7 +434,15 @@ class StatisticsAdminTestCase extends DrupalWebTestCase {
     variable_set('statistics_flush_accesslog_timer', 1);
 
     $this->drupalGet('node/' . $this->test_node->nid);
+    // Manually calling statistics.php, simulating ajax behavior.
+    $nid = $this->test_node->nid;
+    $post = http_build_query(array('nid' => $nid));
+    $headers = array('Content-Type' => 'application/x-www-form-urlencoded');
+    global $base_url;
+    $stats_path = $base_url . '/' . drupal_get_path('module', 'statistics'). '/statistics.php';
+    drupal_http_request($stats_path, array('method' => 'POST', 'data' => $post, 'headers' => $headers, 'timeout' => 10000));
     $this->drupalGet('node/' . $this->test_node->nid);
+    drupal_http_request($stats_path, array('method' => 'POST', 'data' => $post, 'headers' => $headers, 'timeout' => 10000));
     $this->assertText('1 read', t('Node is read once.'));
 
     $this->drupalGet('admin/reports/pages');
@@ -446,6 +491,13 @@ class StatisticsTokenReplaceTestCase extends StatisticsTestCase {
 
     // Hit the node.
     $this->drupalGet('node/' . $node->nid);
+    // Manually calling statistics.php, simulating ajax behavior.
+    $nid = $node->nid;
+    $post = http_build_query(array('nid' => $nid));
+    $headers = array('Content-Type' => 'application/x-www-form-urlencoded');
+    global $base_url;
+    $stats_path = $base_url . '/' . drupal_get_path('module', 'statistics'). '/statistics.php';
+    drupal_http_request($stats_path, array('method' => 'POST', 'data' => $post, 'headers' => $headers, 'timeout' => 10000));
     $statistics = statistics_get($node->nid);
 
     // Generate and test tokens.
