diff --git a/crop.module b/crop.module
index 0aad0d1..424692f 100644
--- a/crop.module
+++ b/crop.module
@@ -8,6 +8,9 @@
  */
 
 use \Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\StreamWrapper\PublicStream;
+use Drupal\crop\Entity\Crop;
+use Drupal\image\Entity\ImageStyle;
 use \Drupal\media_entity\MediaBundleInterface;
 use \Drupal\file\FileInterface;
 
@@ -108,3 +111,45 @@ function crop_file_delete(FileInterface $file) {
     $crop->delete();
   }
 }
+
+/**
+ * Implements hook_file_url_alter().
+ */
+function crop_file_url_alter(&$uri) {
+  // Parse given URI.
+  $uri_info = parse_url($uri);
+  // Use schema information to skip relative URIs.
+  $protocol = isset($uri_info['scheme']) ? in_array($uri_info['scheme'], ['http', 'https']) : FALSE;
+
+  // Process only files that are stored in "styles" directory.
+  if ($protocol && strpos($uri, PublicStream::basePath() . '/styles/') !== FALSE) {
+    // Match image style, schema, file subdirectory and file name.
+    preg_match("/styles\/(.*?)\/(.*?)\/(.*?)\?/", $uri, $match);
+    // Get the image style ID.
+    $image_style = $match[1];
+    // Get the file URI using parsed schema and file path.
+    $file_uri = $match[2] . '://' . $match[3];
+
+    /** @var \Drupal\image\Entity\ImageStyle $image_style */
+    $image_style = ImageStyle::load($image_style);
+
+    $crop_type = NULL;
+    // Find whether matched image style uses "crop_type" effect.
+    /* @var  \Drupal\image\ImageEffectInterface $effect */
+    foreach ($image_style->getEffects() as $uuid => $effect) {
+      $data_effect = $image_style->getEffect($uuid)->getConfiguration()['data'];
+      if (isset($data_effect['crop_type'])) {
+        $crop_type = $data_effect['crop_type'];
+        break;
+      }
+    }
+
+    // In case the image style uses "crop_type" effect, load the crop entity.
+    if ($crop_type && $crop = Crop::findCrop($file_uri, $crop_type)) {
+      // Found a crop for this image, append a hash of it to the URL,
+      // so that browsers reload the image and CDNs and proxies can be bypassed.
+      $shortened_hash = substr(md5(implode($crop->position()) . implode($crop->anchor())), 0, 8);
+      $uri .= '&h=' . $shortened_hash;
+    }
+  }
+}
