diff --git a/linkchecker.module b/linkchecker.module
index bc1abf9..c158e51 100644
--- a/linkchecker.module
+++ b/linkchecker.module
@@ -609,6 +609,14 @@ function _linkchecker_status_handling(&$response, $link) {
             $node_original = clone $node;
             $node = _linkchecker_replace_fields('node', $node->type, $node, $link->url, $response->redirect_url);
 
+            // Allow modules to replace link in custom attributes.
+            // Modules implementing this should call _linkchecker_link_replace().
+            $context = array(
+              'old' => $link->url,
+              'new' => $response->redirect_url,
+            );
+            drupal_alter('linkchecker_replace_link', $node, $context);
+
             if ($node_original != $node) {
               // Always use the default revision setting. For more information,
               // see node_object_prepare().
@@ -1053,6 +1061,10 @@ function _linkchecker_extract_node_links($node, $return_field_names = FALSE) {
   $text_items_by_field['title'][] = _filter_url($node->title, $filter);
   $text_items = _linkchecker_array_values_recursive($text_items_by_field);
 
+  // Allow modules to provide additional text items.
+  $module_text_items = module_invoke_all('linkchecker_extract_node_links', $node);
+  $text_items = array_merge($text_items, $module_text_items);
+
   // Get the absolute node path for extraction of relative links.
   $languages = language_list();
   // Note: An "undefined language" (value: 'und') isn't listed in the available
